| .. | .. |
|---|
| 23 | 23 | * |
|---|
| 24 | 24 | */ |
|---|
| 25 | 25 | |
|---|
| 26 | +#include <linux/slab.h> |
|---|
| 27 | + |
|---|
| 26 | 28 | #include "dm_services.h" |
|---|
| 27 | 29 | #include "dm_helpers.h" |
|---|
| 28 | 30 | #include "gpio_service_interface.h" |
|---|
| .. | .. |
|---|
| 33 | 35 | #include "include/vector.h" |
|---|
| 34 | 36 | #include "core_types.h" |
|---|
| 35 | 37 | #include "dc_link_ddc.h" |
|---|
| 36 | | -#include "aux_engine.h" |
|---|
| 38 | +#include "dce/dce_aux.h" |
|---|
| 37 | 39 | |
|---|
| 38 | 40 | #define AUX_POWER_UP_WA_DELAY 500 |
|---|
| 39 | 41 | #define I2C_OVER_AUX_DEFER_WA_DELAY 70 |
|---|
| .. | .. |
|---|
| 42 | 44 | #define CV_SMART_DONGLE_ADDRESS 0x20 |
|---|
| 43 | 45 | /* DVI-HDMI dongle slave address for retrieving dongle signature*/ |
|---|
| 44 | 46 | #define DVI_HDMI_DONGLE_ADDRESS 0x68 |
|---|
| 45 | | -static const int8_t dvi_hdmi_dongle_signature_str[] = "6140063500G"; |
|---|
| 46 | 47 | struct dvi_hdmi_dongle_signature_data { |
|---|
| 47 | 48 | int8_t vendor[3];/* "AMD" */ |
|---|
| 48 | 49 | uint8_t version[2]; |
|---|
| .. | .. |
|---|
| 92 | 93 | uint8_t CH2_LOCKED:1; |
|---|
| 93 | 94 | uint8_t RESERVED:4; |
|---|
| 94 | 95 | uint8_t RESERVED2:8; |
|---|
| 96 | + uint8_t RESERVED3:8; |
|---|
| 97 | + |
|---|
| 95 | 98 | } fields; |
|---|
| 96 | 99 | }; |
|---|
| 97 | 100 | |
|---|
| .. | .. |
|---|
| 108 | 111 | uint8_t CH2_7HIGH:7; |
|---|
| 109 | 112 | uint8_t CH2_VALID:1; |
|---|
| 110 | 113 | uint8_t CHECKSUM:8; |
|---|
| 111 | | - } fields; |
|---|
| 112 | | -}; |
|---|
| 113 | | - |
|---|
| 114 | | -union hdmi_scdc_test_config_Data { |
|---|
| 115 | | - uint8_t byte; |
|---|
| 116 | | - struct { |
|---|
| 117 | | - uint8_t TEST_READ_REQUEST_DELAY:7; |
|---|
| 118 | | - uint8_t TEST_READ_REQUEST: 1; |
|---|
| 114 | + uint8_t RESERVED:8; |
|---|
| 115 | + uint8_t RESERVED2:8; |
|---|
| 116 | + uint8_t RESERVED3:8; |
|---|
| 117 | + uint8_t RESERVED4:4; |
|---|
| 119 | 118 | } fields; |
|---|
| 120 | 119 | }; |
|---|
| 121 | 120 | |
|---|
| .. | .. |
|---|
| 149 | 148 | return p->payloads.count; |
|---|
| 150 | 149 | } |
|---|
| 151 | 150 | |
|---|
| 152 | | -static void dal_ddc_i2c_payloads_destroy(struct i2c_payloads *p) |
|---|
| 153 | | -{ |
|---|
| 154 | | - if (!p) |
|---|
| 155 | | - return; |
|---|
| 156 | | - |
|---|
| 157 | | - dal_vector_destruct(&p->payloads); |
|---|
| 158 | | -} |
|---|
| 159 | | - |
|---|
| 160 | | -static struct aux_payloads *dal_ddc_aux_payloads_create(struct dc_context *ctx, uint32_t count) |
|---|
| 161 | | -{ |
|---|
| 162 | | - struct aux_payloads *payloads; |
|---|
| 163 | | - |
|---|
| 164 | | - payloads = kzalloc(sizeof(struct aux_payloads), GFP_KERNEL); |
|---|
| 165 | | - |
|---|
| 166 | | - if (!payloads) |
|---|
| 167 | | - return NULL; |
|---|
| 168 | | - |
|---|
| 169 | | - if (dal_vector_construct( |
|---|
| 170 | | - &payloads->payloads, ctx, count, sizeof(struct aux_payload))) |
|---|
| 171 | | - return payloads; |
|---|
| 172 | | - |
|---|
| 173 | | - kfree(payloads); |
|---|
| 174 | | - return NULL; |
|---|
| 175 | | -} |
|---|
| 176 | | - |
|---|
| 177 | | -static struct aux_payload *dal_ddc_aux_payloads_get(struct aux_payloads *p) |
|---|
| 178 | | -{ |
|---|
| 179 | | - return (struct aux_payload *)p->payloads.container; |
|---|
| 180 | | -} |
|---|
| 181 | | - |
|---|
| 182 | | -static uint32_t dal_ddc_aux_payloads_get_count(struct aux_payloads *p) |
|---|
| 183 | | -{ |
|---|
| 184 | | - return p->payloads.count; |
|---|
| 185 | | -} |
|---|
| 186 | | - |
|---|
| 187 | | -static void dal_ddc_aux_payloads_destroy(struct aux_payloads **p) |
|---|
| 188 | | -{ |
|---|
| 189 | | - if (!p || !*p) |
|---|
| 190 | | - return; |
|---|
| 191 | | - |
|---|
| 192 | | - dal_vector_destruct(&(*p)->payloads); |
|---|
| 193 | | - kfree(*p); |
|---|
| 194 | | - *p = NULL; |
|---|
| 195 | | -} |
|---|
| 196 | | - |
|---|
| 197 | 151 | #define DDC_MIN(a, b) (((a) < (b)) ? (a) : (b)) |
|---|
| 198 | 152 | |
|---|
| 199 | 153 | void dal_ddc_i2c_payloads_add( |
|---|
| .. | .. |
|---|
| 217 | 171 | |
|---|
| 218 | 172 | } |
|---|
| 219 | 173 | |
|---|
| 220 | | -void dal_ddc_aux_payloads_add( |
|---|
| 221 | | - struct aux_payloads *payloads, |
|---|
| 222 | | - uint32_t address, |
|---|
| 223 | | - uint32_t len, |
|---|
| 224 | | - uint8_t *data, |
|---|
| 225 | | - bool write) |
|---|
| 226 | | -{ |
|---|
| 227 | | - uint32_t payload_size = DEFAULT_AUX_MAX_DATA_SIZE; |
|---|
| 228 | | - uint32_t pos; |
|---|
| 229 | | - |
|---|
| 230 | | - for (pos = 0; pos < len; pos += payload_size) { |
|---|
| 231 | | - struct aux_payload payload = { |
|---|
| 232 | | - .i2c_over_aux = true, |
|---|
| 233 | | - .write = write, |
|---|
| 234 | | - .address = address, |
|---|
| 235 | | - .length = DDC_MIN(payload_size, len - pos), |
|---|
| 236 | | - .data = data + pos }; |
|---|
| 237 | | - dal_vector_append(&payloads->payloads, &payload); |
|---|
| 238 | | - } |
|---|
| 239 | | -} |
|---|
| 240 | | - |
|---|
| 241 | | -static void construct( |
|---|
| 174 | +static void ddc_service_construct( |
|---|
| 242 | 175 | struct ddc_service *ddc_service, |
|---|
| 243 | 176 | struct ddc_service_init_data *init_data) |
|---|
| 244 | 177 | { |
|---|
| .. | .. |
|---|
| 257 | 190 | ddc_service->ddc_pin = NULL; |
|---|
| 258 | 191 | } else { |
|---|
| 259 | 192 | hw_info.ddc_channel = i2c_info.i2c_line; |
|---|
| 260 | | - hw_info.hw_supported = i2c_info.i2c_hw_assist; |
|---|
| 193 | + if (ddc_service->link != NULL) |
|---|
| 194 | + hw_info.hw_supported = i2c_info.i2c_hw_assist; |
|---|
| 195 | + else |
|---|
| 196 | + hw_info.hw_supported = false; |
|---|
| 261 | 197 | |
|---|
| 262 | 198 | ddc_service->ddc_pin = dal_gpio_create_ddc( |
|---|
| 263 | 199 | gpio_service, |
|---|
| .. | .. |
|---|
| 287 | 223 | if (!ddc_service) |
|---|
| 288 | 224 | return NULL; |
|---|
| 289 | 225 | |
|---|
| 290 | | - construct(ddc_service, init_data); |
|---|
| 226 | + ddc_service_construct(ddc_service, init_data); |
|---|
| 291 | 227 | return ddc_service; |
|---|
| 292 | 228 | } |
|---|
| 293 | 229 | |
|---|
| 294 | | -static void destruct(struct ddc_service *ddc) |
|---|
| 230 | +static void ddc_service_destruct(struct ddc_service *ddc) |
|---|
| 295 | 231 | { |
|---|
| 296 | 232 | if (ddc->ddc_pin) |
|---|
| 297 | 233 | dal_gpio_destroy_ddc(&ddc->ddc_pin); |
|---|
| .. | .. |
|---|
| 303 | 239 | BREAK_TO_DEBUGGER(); |
|---|
| 304 | 240 | return; |
|---|
| 305 | 241 | } |
|---|
| 306 | | - destruct(*ddc); |
|---|
| 242 | + ddc_service_destruct(*ddc); |
|---|
| 307 | 243 | kfree(*ddc); |
|---|
| 308 | 244 | *ddc = NULL; |
|---|
| 309 | 245 | } |
|---|
| .. | .. |
|---|
| 345 | 281 | { |
|---|
| 346 | 282 | struct dc_link *link = ddc->link; |
|---|
| 347 | 283 | |
|---|
| 348 | | - if (link->dpcd_caps.branch_dev_id == DP_BRANCH_DEVICE_ID_4 && |
|---|
| 284 | + if (link->dpcd_caps.branch_dev_id == DP_BRANCH_DEVICE_ID_0080E1 && |
|---|
| 349 | 285 | !memcmp(link->dpcd_caps.branch_dev_name, |
|---|
| 350 | 286 | DP_DVI_CONVERTER_ID_4, |
|---|
| 351 | 287 | sizeof(link->dpcd_caps.branch_dev_name))) |
|---|
| .. | .. |
|---|
| 559 | 495 | uint8_t *read_buf, |
|---|
| 560 | 496 | uint32_t read_size) |
|---|
| 561 | 497 | { |
|---|
| 562 | | - bool ret; |
|---|
| 498 | + bool success = true; |
|---|
| 563 | 499 | uint32_t payload_size = |
|---|
| 564 | 500 | dal_ddc_service_is_in_aux_transaction_mode(ddc) ? |
|---|
| 565 | 501 | DEFAULT_AUX_MAX_DATA_SIZE : EDID_SEGMENT_SIZE; |
|---|
| .. | .. |
|---|
| 582 | 518 | /*TODO: len of payload data for i2c and aux is uint8!!!!, |
|---|
| 583 | 519 | * but we want to read 256 over i2c!!!!*/ |
|---|
| 584 | 520 | if (dal_ddc_service_is_in_aux_transaction_mode(ddc)) { |
|---|
| 521 | + struct aux_payload payload; |
|---|
| 585 | 522 | |
|---|
| 586 | | - struct aux_payloads *payloads = |
|---|
| 587 | | - dal_ddc_aux_payloads_create(ddc->ctx, payloads_num); |
|---|
| 523 | + payload.i2c_over_aux = true; |
|---|
| 524 | + payload.address = address; |
|---|
| 525 | + payload.reply = NULL; |
|---|
| 526 | + payload.defer_delay = get_defer_delay(ddc); |
|---|
| 588 | 527 | |
|---|
| 589 | | - struct aux_command command = { |
|---|
| 590 | | - .payloads = dal_ddc_aux_payloads_get(payloads), |
|---|
| 591 | | - .number_of_payloads = 0, |
|---|
| 592 | | - .defer_delay = get_defer_delay(ddc), |
|---|
| 593 | | - .max_defer_write_retry = 0 }; |
|---|
| 528 | + if (write_size != 0) { |
|---|
| 529 | + payload.write = true; |
|---|
| 530 | + /* should not set mot (middle of transaction) to 0 |
|---|
| 531 | + * if there are pending read payloads |
|---|
| 532 | + */ |
|---|
| 533 | + payload.mot = read_size == 0 ? false : true; |
|---|
| 534 | + payload.length = write_size; |
|---|
| 535 | + payload.data = write_buf; |
|---|
| 594 | 536 | |
|---|
| 595 | | - dal_ddc_aux_payloads_add( |
|---|
| 596 | | - payloads, address, write_size, write_buf, true); |
|---|
| 537 | + success = dal_ddc_submit_aux_command(ddc, &payload); |
|---|
| 538 | + } |
|---|
| 597 | 539 | |
|---|
| 598 | | - dal_ddc_aux_payloads_add( |
|---|
| 599 | | - payloads, address, read_size, read_buf, false); |
|---|
| 540 | + if (read_size != 0 && success) { |
|---|
| 541 | + payload.write = false; |
|---|
| 542 | + /* should set mot (middle of transaction) to 0 |
|---|
| 543 | + * since it is the last payload to send |
|---|
| 544 | + */ |
|---|
| 545 | + payload.mot = false; |
|---|
| 546 | + payload.length = read_size; |
|---|
| 547 | + payload.data = read_buf; |
|---|
| 600 | 548 | |
|---|
| 601 | | - command.number_of_payloads = |
|---|
| 602 | | - dal_ddc_aux_payloads_get_count(payloads); |
|---|
| 603 | | - |
|---|
| 604 | | - ret = dal_i2caux_submit_aux_command( |
|---|
| 605 | | - ddc->ctx->i2caux, |
|---|
| 606 | | - ddc->ddc_pin, |
|---|
| 607 | | - &command); |
|---|
| 608 | | - |
|---|
| 609 | | - dal_ddc_aux_payloads_destroy(&payloads); |
|---|
| 610 | | - |
|---|
| 549 | + success = dal_ddc_submit_aux_command(ddc, &payload); |
|---|
| 550 | + } |
|---|
| 611 | 551 | } else { |
|---|
| 612 | 552 | struct i2c_command command = {0}; |
|---|
| 613 | 553 | struct i2c_payloads payloads; |
|---|
| .. | .. |
|---|
| 629 | 569 | command.number_of_payloads = |
|---|
| 630 | 570 | dal_ddc_i2c_payloads_get_count(&payloads); |
|---|
| 631 | 571 | |
|---|
| 632 | | - ret = dm_helpers_submit_i2c( |
|---|
| 572 | + success = dm_helpers_submit_i2c( |
|---|
| 633 | 573 | ddc->ctx, |
|---|
| 634 | 574 | ddc->link, |
|---|
| 635 | 575 | &command); |
|---|
| 636 | 576 | |
|---|
| 637 | | - dal_ddc_i2c_payloads_destroy(&payloads); |
|---|
| 577 | + dal_vector_destruct(&payloads.payloads); |
|---|
| 638 | 578 | } |
|---|
| 579 | + |
|---|
| 580 | + return success; |
|---|
| 581 | +} |
|---|
| 582 | + |
|---|
| 583 | +bool dal_ddc_submit_aux_command(struct ddc_service *ddc, |
|---|
| 584 | + struct aux_payload *payload) |
|---|
| 585 | +{ |
|---|
| 586 | + uint32_t retrieved = 0; |
|---|
| 587 | + bool ret = false; |
|---|
| 588 | + |
|---|
| 589 | + if (!ddc) |
|---|
| 590 | + return false; |
|---|
| 591 | + |
|---|
| 592 | + if (!payload) |
|---|
| 593 | + return false; |
|---|
| 594 | + |
|---|
| 595 | + do { |
|---|
| 596 | + struct aux_payload current_payload; |
|---|
| 597 | + bool is_end_of_payload = (retrieved + DEFAULT_AUX_MAX_DATA_SIZE) >= |
|---|
| 598 | + payload->length; |
|---|
| 599 | + |
|---|
| 600 | + current_payload.address = payload->address; |
|---|
| 601 | + current_payload.data = &payload->data[retrieved]; |
|---|
| 602 | + current_payload.defer_delay = payload->defer_delay; |
|---|
| 603 | + current_payload.i2c_over_aux = payload->i2c_over_aux; |
|---|
| 604 | + current_payload.length = is_end_of_payload ? |
|---|
| 605 | + payload->length - retrieved : DEFAULT_AUX_MAX_DATA_SIZE; |
|---|
| 606 | + /* set mot (middle of transaction) to false |
|---|
| 607 | + * if it is the last payload |
|---|
| 608 | + */ |
|---|
| 609 | + current_payload.mot = is_end_of_payload ? payload->mot:true; |
|---|
| 610 | + current_payload.reply = payload->reply; |
|---|
| 611 | + current_payload.write = payload->write; |
|---|
| 612 | + |
|---|
| 613 | + ret = dc_link_aux_transfer_with_retries(ddc, ¤t_payload); |
|---|
| 614 | + |
|---|
| 615 | + retrieved += current_payload.length; |
|---|
| 616 | + } while (retrieved < payload->length && ret == true); |
|---|
| 639 | 617 | |
|---|
| 640 | 618 | return ret; |
|---|
| 641 | 619 | } |
|---|
| 642 | 620 | |
|---|
| 643 | | -int dc_link_aux_transfer(struct ddc_service *ddc, |
|---|
| 644 | | - unsigned int address, |
|---|
| 645 | | - uint8_t *reply, |
|---|
| 646 | | - void *buffer, |
|---|
| 647 | | - unsigned int size, |
|---|
| 648 | | - enum aux_transaction_type type, |
|---|
| 649 | | - enum i2caux_transaction_action action) |
|---|
| 621 | +/* dc_link_aux_transfer_raw() - Attempt to transfer |
|---|
| 622 | + * the given aux payload. This function does not perform |
|---|
| 623 | + * retries or handle error states. The reply is returned |
|---|
| 624 | + * in the payload->reply and the result through |
|---|
| 625 | + * *operation_result. Returns the number of bytes transferred, |
|---|
| 626 | + * or -1 on a failure. |
|---|
| 627 | + */ |
|---|
| 628 | +int dc_link_aux_transfer_raw(struct ddc_service *ddc, |
|---|
| 629 | + struct aux_payload *payload, |
|---|
| 630 | + enum aux_channel_operation_result *operation_result) |
|---|
| 650 | 631 | { |
|---|
| 632 | + return dce_aux_transfer_raw(ddc, payload, operation_result); |
|---|
| 633 | +} |
|---|
| 634 | + |
|---|
| 635 | +/* dc_link_aux_transfer_with_retries() - Attempt to submit an |
|---|
| 636 | + * aux payload, retrying on timeouts, defers, and busy states |
|---|
| 637 | + * as outlined in the DP spec. Returns true if the request |
|---|
| 638 | + * was successful. |
|---|
| 639 | + * |
|---|
| 640 | + * Unless you want to implement your own retry semantics, this |
|---|
| 641 | + * is probably the one you want. |
|---|
| 642 | + */ |
|---|
| 643 | +bool dc_link_aux_transfer_with_retries(struct ddc_service *ddc, |
|---|
| 644 | + struct aux_payload *payload) |
|---|
| 645 | +{ |
|---|
| 646 | + return dce_aux_transfer_with_retries(ddc, payload); |
|---|
| 647 | +} |
|---|
| 648 | + |
|---|
| 649 | + |
|---|
| 650 | +bool dc_link_aux_try_to_configure_timeout(struct ddc_service *ddc, |
|---|
| 651 | + uint32_t timeout) |
|---|
| 652 | +{ |
|---|
| 653 | + bool result = false; |
|---|
| 651 | 654 | struct ddc *ddc_pin = ddc->ddc_pin; |
|---|
| 652 | | - struct aux_engine *aux_engine; |
|---|
| 653 | | - enum aux_channel_operation_result operation_result; |
|---|
| 654 | | - struct aux_request_transaction_data aux_req; |
|---|
| 655 | | - struct aux_reply_transaction_data aux_rep; |
|---|
| 656 | | - uint8_t returned_bytes = 0; |
|---|
| 657 | | - int res = -1; |
|---|
| 658 | | - uint32_t status; |
|---|
| 659 | 655 | |
|---|
| 660 | | - memset(&aux_req, 0, sizeof(aux_req)); |
|---|
| 661 | | - memset(&aux_rep, 0, sizeof(aux_rep)); |
|---|
| 662 | | - |
|---|
| 663 | | - aux_engine = ddc->ctx->dc->res_pool->engines[ddc_pin->pin_data->en]; |
|---|
| 664 | | - aux_engine->funcs->acquire(aux_engine, ddc_pin); |
|---|
| 665 | | - |
|---|
| 666 | | - aux_req.type = type; |
|---|
| 667 | | - aux_req.action = action; |
|---|
| 668 | | - |
|---|
| 669 | | - aux_req.address = address; |
|---|
| 670 | | - aux_req.delay = 0; |
|---|
| 671 | | - aux_req.length = size; |
|---|
| 672 | | - aux_req.data = buffer; |
|---|
| 673 | | - |
|---|
| 674 | | - aux_engine->funcs->submit_channel_request(aux_engine, &aux_req); |
|---|
| 675 | | - operation_result = aux_engine->funcs->get_channel_status(aux_engine, &returned_bytes); |
|---|
| 676 | | - |
|---|
| 677 | | - switch (operation_result) { |
|---|
| 678 | | - case AUX_CHANNEL_OPERATION_SUCCEEDED: |
|---|
| 679 | | - res = returned_bytes; |
|---|
| 680 | | - |
|---|
| 681 | | - if (res <= size && res >= 0) |
|---|
| 682 | | - res = aux_engine->funcs->read_channel_reply(aux_engine, size, |
|---|
| 683 | | - buffer, reply, |
|---|
| 684 | | - &status); |
|---|
| 685 | | - |
|---|
| 686 | | - break; |
|---|
| 687 | | - case AUX_CHANNEL_OPERATION_FAILED_HPD_DISCON: |
|---|
| 688 | | - res = 0; |
|---|
| 689 | | - break; |
|---|
| 690 | | - case AUX_CHANNEL_OPERATION_FAILED_REASON_UNKNOWN: |
|---|
| 691 | | - case AUX_CHANNEL_OPERATION_FAILED_INVALID_REPLY: |
|---|
| 692 | | - case AUX_CHANNEL_OPERATION_FAILED_TIMEOUT: |
|---|
| 693 | | - res = -1; |
|---|
| 694 | | - break; |
|---|
| 656 | + if (ddc->ctx->dc->res_pool->engines[ddc_pin->pin_data->en]->funcs->configure_timeout) { |
|---|
| 657 | + ddc->ctx->dc->res_pool->engines[ddc_pin->pin_data->en]->funcs->configure_timeout(ddc, timeout); |
|---|
| 658 | + result = true; |
|---|
| 695 | 659 | } |
|---|
| 696 | | - aux_engine->funcs->release_engine(aux_engine); |
|---|
| 697 | | - return res; |
|---|
| 660 | + return result; |
|---|
| 698 | 661 | } |
|---|
| 699 | 662 | |
|---|
| 700 | 663 | /*test only function*/ |
|---|
| .. | .. |
|---|
| 720 | 683 | uint8_t sink_version = 0; |
|---|
| 721 | 684 | uint8_t write_buffer[2] = {0}; |
|---|
| 722 | 685 | /*Lower than 340 Scramble bit from SCDC caps*/ |
|---|
| 686 | + |
|---|
| 687 | + if (ddc_service->link->local_sink && |
|---|
| 688 | + ddc_service->link->local_sink->edid_caps.panel_patch.skip_scdc_overwrite) |
|---|
| 689 | + return; |
|---|
| 723 | 690 | |
|---|
| 724 | 691 | dal_ddc_service_query_ddc_data(ddc_service, slave_address, &offset, |
|---|
| 725 | 692 | sizeof(offset), &sink_version, sizeof(sink_version)); |
|---|
| .. | .. |
|---|
| 750 | 717 | uint8_t offset = HDMI_SCDC_TMDS_CONFIG; |
|---|
| 751 | 718 | uint8_t tmds_config = 0; |
|---|
| 752 | 719 | |
|---|
| 720 | + if (ddc_service->link->local_sink && |
|---|
| 721 | + ddc_service->link->local_sink->edid_caps.panel_patch.skip_scdc_overwrite) |
|---|
| 722 | + return; |
|---|
| 723 | + |
|---|
| 753 | 724 | dal_ddc_service_query_ddc_data(ddc_service, slave_address, &offset, |
|---|
| 754 | 725 | sizeof(offset), &tmds_config, sizeof(tmds_config)); |
|---|
| 755 | 726 | if (tmds_config & 0x1) { |
|---|