//****************************************************************************** /// \brief Read packet from MXT chip /// \return #mxt_rc static int hidraw_read_response(struct mxt_device *mxt, struct hid_packet *read_pkt, size_t count) { ssize_t ret = 0; size_t t_count = 0; int timeout = 0; do { ret = read(mxt->conn->hidraw.fd, read_pkt + t_count, count); if ((size_t)ret != count) { mxt_dbg(mxt->ctx, "Error %s (%d) reading from hidraw", strerror(errno), errno); ret = mxt_errno_to_rc(errno); } else { t_count += (size_t)ret; } usleep(HIDRAW_READ_RETRY_DELAY_US); } while (timeout++ <= HIDRAW_TIMEOUT_DELAY_US && t_count != count); mxt_dbg(mxt->ctx, "No. bytes requested: %zu, No. of bytes read: %zu", count, t_count); mxt_log_buffer(mxt->ctx, LOG_VERBOSE, "RD PKT RX:", (const unsigned char *) read_pkt, count); return MXT_SUCCESS; }
//****************************************************************************** /// \brief Read register from MXT chip /// \return #mxt_rc int hidraw_read_register(struct mxt_device *mxt, unsigned char *buf, uint16_t start_register, int count) { int ret; struct hid_packet read_pkt = { 0 }; mxt_dbg(mxt->ctx, "%s - start_register:%d No. bytes requested:%d", __func__, start_register, count); ret = hidraw_open(mxt); if (ret) return ret; int bytes_read = 0; while (bytes_read < count) { ret = hidraw_read_packet(mxt, &read_pkt, start_register + bytes_read, (count - bytes_read <= MXT_HID_READ_DATA_SIZE ? count - bytes_read : MXT_HID_READ_DATA_SIZE)); if (ret < 0) { mxt_dbg(mxt->ctx, "read error %s (%d)", strerror(errno), errno); ret = mxt_errno_to_rc(errno); } memcpy(buf + bytes_read, read_pkt.read_data, ret); bytes_read += ret; } close(mxt->conn->hidraw.fd); mxt->conn->hidraw.fd = 0; return MXT_SUCCESS; }
//****************************************************************************** /// \brief Write register from MXT chip /// \return #mxt_rc int hidraw_write_register(struct mxt_device *mxt, unsigned char const *val, uint16_t start_register, int datalength) { int ret; uint8_t byte_count; struct hid_packet write_pkt; memset(&write_pkt, 0x00, sizeof(struct hid_packet)); write_pkt.report_id = mxt->conn->hidraw.report_id; write_pkt.cmd = 0x51; write_pkt.tx_bytes = 0; mxt_dbg(mxt->ctx, "%s - start_register:%d No. bytes to write:%d", __func__, start_register, datalength); ret = hidraw_open(mxt); if (ret) return ret; int bytes_written = 0; while (bytes_written < datalength) { write_pkt.rx_bytes = MXT_HID_ADDR_SIZE + (datalength - bytes_written <= MXT_HID_WRITE_DATA_SIZE ? datalength - bytes_written : MXT_HID_WRITE_DATA_SIZE); write_pkt.address = htole16(start_register + bytes_written); memcpy(write_pkt.write_data, val + bytes_written, write_pkt.rx_bytes); ret = hidraw_write_packet(mxt, &write_pkt, &byte_count); if (ret) { mxt_err(mxt->ctx, "read error %s (%d)", strerror(errno), errno); ret = mxt_errno_to_rc(errno); goto close; } bytes_written += byte_count; mxt_dbg(mxt->ctx, "Bytes Written:%d", bytes_written); struct hid_packet response_pkt; memset(&response_pkt, 0x00, sizeof(struct hid_packet)); ret = hidraw_read_response(mxt, &response_pkt, 2); if (response_pkt.result != MXT_HID_READ_SUCCESS) mxt_err(mxt->ctx, "HIDRAW write failed: 0x%x", response_pkt.result); } close: close(mxt->conn->hidraw.fd); mxt->conn->hidraw.fd = 0; return MXT_SUCCESS; }
//****************************************************************************** /// \brief Read one frame of diagnostic data /// \return #mxt_rc int mxt_read_diagnostic_data_frame(struct t37_ctx* ctx) { int ret; /* iterate through stripes */ for (ctx->pass = 0; ctx->pass < ctx->passes; ctx->pass++) { /* Calculate stripe parameters */ ctx->stripe_starty = ctx->stripe_width * ctx->pass; ctx->stripe_endy = ctx->stripe_starty + ctx->stripe_width - 1; ctx->x_ptr = 0; ctx->y_ptr = ctx->stripe_starty; for (ctx->page = 0; ctx->page < ctx->pages_per_pass; ctx->page++) { mxt_dbg(ctx->lc, "Frame %d Pass %d Page %d", ctx->frame, ctx->pass, ctx->page); ret = mxt_get_t37_page(ctx); if (ret) return ret; mxt_debug_insert_data(ctx); } } return MXT_SUCCESS; }
//****************************************************************************** /// \brief Wait for messages int mxt_msg_wait(struct mxt_device *mxt, int timeout_ms) { int ret; int fd = 0; int numfds = 0; struct pollfd fds[1]; fd = mxt_get_msg_poll_fd(mxt); if (fd) { fds[0].fd = fd; fds[0].events = POLLPRI; numfds = 1; } ret = poll(fds, numfds, timeout_ms); if (ret == -1 && errno == EINTR) { mxt_dbg(mxt->ctx, "Interrupted"); return MXT_ERROR_INTERRUPTED; } else if (ret < 0) { mxt_err(mxt->ctx, "poll returned %d (%s)", errno, strerror(errno)); return MXT_ERROR_IO; } return MXT_SUCCESS; }
//****************************************************************************** /// \brief Get T5 message as string /// \return Message string (null for no message) char *mxt_get_msg_string(struct mxt_device *mxt) { char *msg_string = NULL; switch (mxt->conn->type) { case E_SYSFS: if (sysfs_has_debug_v2(mxt)) msg_string = sysfs_get_msg_string_v2(mxt); else msg_string = dmesg_get_msg_string(mxt); break; #ifdef HAVE_LIBUSB case E_USB: #endif /* HAVE_LIBUSB */ case E_I2C_DEV: case E_HIDRAW: msg_string = t44_get_msg_string(mxt); break; default: mxt_err(mxt->ctx, "Device type not supported"); break; } if (msg_string) mxt_dbg(mxt->ctx, "%s", msg_string); return msg_string; }
//****************************************************************************** /// \brief Write packet to MXT chip /// \return Number of databytes sent static int hidraw_write_packet(struct mxt_device *mxt, struct hid_packet *write_pkt, uint8_t *byte_count) { int ret; uint8_t pkt_size = write_pkt->rx_bytes + 4; /* allowing for header */ if ((ret = write(mxt->conn->hidraw.fd, write_pkt, pkt_size)) != pkt_size) { mxt_verb(mxt->ctx, "HIDRAW retry"); usleep(HIDRAW_WRITE_RETRY_DELAY_US); if ((ret = write(mxt->conn->hidraw.fd, &write_pkt, pkt_size)) != pkt_size) { mxt_err(mxt->ctx, "Error %s (%d) writing to hidraw", strerror(errno), errno); ret = mxt_errno_to_rc(errno); } } mxt_log_buffer(mxt->ctx, LOG_VERBOSE, "PKT TX:", (const unsigned char *) write_pkt, pkt_size); *byte_count = ret - 6; mxt_dbg(mxt->ctx, "Sending packet: size: %d No. data bytes TX: %d", pkt_size, *byte_count); return MXT_SUCCESS; }
//****************************************************************************** /// \brief Retrieve a single page of diagnostic data /// \return #mxt_rc static int mxt_get_t37_page(struct t37_ctx *ctx) { int failures; int ret; uint8_t read_command = 1; uint8_t page_up_cmd = PAGE_UP; if (ctx->pass == 0 && ctx->page == 0) { mxt_dbg(ctx->lc, "Writing mode command %02X", ctx->mode); ret = mxt_write_register(ctx->mxt, &ctx->mode, ctx->diag_cmd_addr, 1); if (ret) return ret; } else { ret = mxt_write_register(ctx->mxt, &page_up_cmd, ctx->diag_cmd_addr, 1); if (ret) return ret; } /* Read back diagnostic register in T6 command processor until it has been * cleared. This means that the chip has actioned the command */ failures = 0; while (read_command) { usleep(500); ret = mxt_read_register(ctx->mxt, &read_command, ctx->diag_cmd_addr, 1); if (ret) { mxt_err(ctx->lc, "Failed to read the status of diagnostic mode command"); return ret; } if (read_command) { failures++; if (failures > 500) { mxt_err(ctx->lc, "Timeout waiting for command to be actioned"); return MXT_ERROR_TIMEOUT; } } } ret = mxt_read_register(ctx->mxt, (uint8_t *)ctx->t37_buf, ctx->t37_addr, ctx->t37_size); if (ret) { mxt_err(ctx->lc, "Failed to read page"); return ret; } if (ctx->t37_buf->mode != ctx->mode) { mxt_err(ctx->lc, "Bad mode in diagnostic data read"); return MXT_ERROR_UNEXPECTED_DEVICE_STATE; } if (ctx->t37_buf->page != (ctx->pages_per_pass * ctx->pass + ctx->page)) { mxt_err(ctx->lc, "Bad page in diagnostic data read"); return MXT_ERROR_UNEXPECTED_DEVICE_STATE; } return MXT_SUCCESS; }
/*! * @brief Logs information about the chip. */ void mxt_display_chip_info(struct mxt_device *mxt) { struct mxt_object obj; char firmware_version[MXT_FW_VER_LEN]; struct mxt_id_info *id = mxt->info.id; int i; mxt_get_firmware_version(mxt, (char *)&firmware_version); /* Display ID information */ mxt_dbg(mxt->ctx, "Family ID = %u (0x%02X)", id->family, id->family); mxt_dbg(mxt->ctx, "Variant ID = %u (0x%02X)", id->variant, id->variant); mxt_dbg(mxt->ctx, "Firmware Version = %s", firmware_version); mxt_dbg(mxt->ctx, "Matrix X Size = %d", id->matrix_x_size); mxt_dbg(mxt->ctx, "Matrix Y Size = %d", id->matrix_y_size); mxt_dbg(mxt->ctx, "Number of elements in the Object Table = %d", id->num_objects); /* Display information about specific objects */ for (i = 0; i < id->num_objects; i++) { obj = mxt->info.objects[i]; mxt_dbg(mxt->ctx, "T%u size:%u instances:%u address:%u", obj.type, MXT_SIZE(obj), MXT_INSTANCES(obj), mxt_get_start_position(obj, 0)); } }
//****************************************************************************** /// \brief Zero entire T68 object /// \return #mxt_rc static int mxt_t68_zero_data(struct t68_ctx *ctx) { uint8_t zeros[ctx->t68_data_size]; mxt_dbg(ctx->lc, "Zeroing DATA"); memset(&zeros, 0, sizeof(zeros)); return mxt_write_register(ctx->mxt, zeros, ctx->t68_addr + T68_DATA, sizeof(zeros)); }
//****************************************************************************** /// \brief Read and deal with incoming command /// \return #mxt_rc static int handle_cmd(struct mxt_device *mxt, int sockfd) { int ret; uint16_t address; uint16_t count; struct mxt_buffer linebuf; char *line; int offset; ret = mxt_buf_init(&linebuf); if (ret) return ret; ret = readline(mxt, sockfd, &linebuf); if (ret) { mxt_dbg(mxt->ctx, "Error reading or peer closed socket"); goto free; } line = (char *)linebuf.data; if (strlen(line) == 0) { ret = MXT_SUCCESS; goto free; } mxt_verb(mxt->ctx, "%s", line); if (!strcmp(line, "SAT")) { mxt_info(mxt->ctx, "Server attached"); ret = MXT_SUCCESS; } else if (!strcmp(line, "SDT")) { mxt_info(mxt->ctx, "Server detached"); ret = MXT_SUCCESS; } else if (sscanf(line, "REA %" SCNu16 " %" SCNu16, &address, &count) == 2) { ret = bridge_rea_cmd(mxt, sockfd, address, count); } else if (sscanf(line, "WRI %" SCNu16 "%n", &address, &offset) == 1) { /* skip space */ offset += 1; ret = bridge_wri_cmd(mxt, sockfd, address, line + offset, strlen(line) - offset); } else { mxt_info(mxt->ctx, "Unrecognised cmd \"%s\"", line); ret = MXT_SUCCESS; } free: mxt_buf_free(&linebuf); return ret; }
//****************************************************************************** /// \brief Enable T68 /// \return #mxt_rc static int mxt_t68_enable(struct t68_ctx *ctx) { int ret; uint8_t cmd = T68_CTRL_RPTEN | T68_CTRL_ENABLE; mxt_dbg(ctx->lc, "Enabling T68 object"); mxt_verb(ctx->lc, "Writing %u to ctrl register", cmd); ret = mxt_write_register(ctx->mxt, &cmd, ctx->t68_addr + T68_CTRL, 1); if (ret) return ret; return MXT_SUCCESS; }
//****************************************************************************** /// \brief Write read command packet to MXT chip /// \return #mxt_rc static int hidraw_write_read_cmd(struct mxt_device *mxt, uint16_t start_register, uint8_t count, uint8_t *byte_count) { struct hid_packet cmd_pkt = { 0 }; cmd_pkt.report_id = mxt->conn->hidraw.report_id; cmd_pkt.cmd = 0x51; cmd_pkt.rx_bytes = 2; /* includes start address word */ cmd_pkt.tx_bytes = count; cmd_pkt.address = htole16(start_register); mxt_dbg(mxt->ctx, "Sending read command"); return hidraw_write_packet(mxt, &cmd_pkt, byte_count); }
//****************************************************************************** /// \brief Open the hidraw dev interface and set the slave address /// \return #mxt_rc static int hidraw_open(struct mxt_device *mxt) { char filename[20]; snprintf(filename, sizeof(filename), "%s", mxt->conn->hidraw.node); mxt->conn->hidraw.fd = open(filename, O_RDWR|O_NONBLOCK); if (mxt->conn->hidraw.fd < 0) { mxt_err(mxt->ctx, "Could not open %s, error %s (%d)", filename, strerror(errno), errno); return mxt_errno_to_rc(errno); } mxt_dbg(mxt->ctx, "Opened %s, fd: %d", filename, mxt->conn->hidraw.fd); return MXT_SUCCESS; }
/*! * @brief Calculates and reports the Information Block Checksum. * @return #mxt_rc */ static int calculate_crc(struct mxt_device *mxt, uint32_t read_crc, uint8_t *base_addr, size_t size) { uint32_t calc_crc = 0; /* Checksum calculated by the driver code */ uint16_t crc_byte_index = 0; /* Call the CRC function crc24() iteratively to calculate the CRC, * passing it two characters at a time. */ while (crc_byte_index < ((size % 2) ? (size - 1) : size)) { calc_crc = crc24(calc_crc, *(base_addr + crc_byte_index), *(base_addr + crc_byte_index + 1)); crc_byte_index += 2; } /* Call crc24() for the final byte, plus an extra * 0 value byte to make the sequence even if it's odd */ if (size % 2) { calc_crc = crc24(calc_crc, *(base_addr + crc_byte_index), 0); } /* Mask 32-bit calculated checksum to 24-bit */ calc_crc &= calc_crc & 0x00FFFFFF; /* A zero CRC indicates a communications error */ if (calc_crc == 0) { mxt_err(mxt->ctx, "Information Block Checksum zero"); return MXT_ERROR_IO; } /* Compare the read checksum with calculated checksum */ if (read_crc != calc_crc) { mxt_err(mxt->ctx, "Information Block Checksum error calc=%06X read=%06X", calc_crc, read_crc); return MXT_ERROR_INFO_CHECKSUM_MISMATCH; } mxt_dbg(mxt->ctx, "Information Block Checksum verified %06X", calc_crc); return MXT_SUCCESS; }
//****************************************************************************** /// \brief Read one frame of diagnostic data /// \return #mxt_rc static int mxt_read_diagnostic_data_self_cap(struct t37_ctx* ctx) { int ret; for (ctx->pass = 0; ctx->pass < ctx->passes; ctx->pass++) { for (ctx->page = 0; ctx->page < ctx->pages_per_pass; ctx->page++) { mxt_dbg(ctx->lc, "Frame %d Pass %d Page %d", ctx->frame, ctx->pass, ctx->page); ret = mxt_get_t37_page(ctx); if (ret) return ret; mxt_debug_insert_data_self_cap(ctx); } } return MXT_SUCCESS; }
//****************************************************************************** /// \brief Handle calibration messages /// \return #mxt_rc static int handle_calibrate_msg(struct mxt_device *mxt, uint8_t *msg, void *context, uint8_t size) { int *last_status = context; int status = msg[1]; if (mxt_report_id_to_type(mxt, msg[0]) == GEN_COMMANDPROCESSOR_T6) { if (status & 0x10) { mxt_dbg(mxt->ctx, "Device calibrating"); } else if (!(status & 0x10) && (*last_status & 0x10)) { mxt_info(mxt->ctx, "Device calibrated"); return MXT_SUCCESS; } *last_status = status; } return MXT_MSG_CONTINUE; }
//****************************************************************************** /// \brief Check sysfs device directory for correct attributes /// \return #mxt_rc static int scan_sysfs_directory(struct libmaxtouch_ctx *ctx, struct mxt_conn_info **conn, struct dirent *i2c_dir, const char *dirname, bool acpi) { char *pszDirname; size_t length; DIR *pDirectory; struct dirent *pEntry; bool mem_access_found = false; bool debug_found = false; bool debug_v2_found = false; int ret; length = strlen(dirname) + strlen(i2c_dir->d_name) + 2; if ((pszDirname = (char *)calloc(length, sizeof(char))) == NULL) { ret = MXT_ERROR_NO_MEM; goto free; } snprintf(pszDirname, length, "%s/%s", dirname, i2c_dir->d_name); pDirectory = opendir(pszDirname); if (!pDirectory) { ret = MXT_ERROR_NO_MEM; goto free; } while ((pEntry = readdir(pDirectory)) != NULL) { if (!strcmp(pEntry->d_name, "mem_access")) { mxt_dbg(ctx, "Found mem_access interface at %s/mem_access", pszDirname); mem_access_found = true; } else if (!strcmp(pEntry->d_name, "debug_enable")) { mxt_dbg(ctx, "Found debug_enable interface at %s/debug_enable", pszDirname); debug_found = true; } else if (!strcmp(pEntry->d_name, "debug_msg")) { mxt_dbg(ctx, "Found Debug V2 at %s/debug_msg", pszDirname); debug_v2_found = true; } } /* If device found, store it and return success */ if (mem_access_found && (debug_found || debug_v2_found)) { ctx->scan_count++; if (ctx->query) { printf("sysfs:%s Atmel %s interface\n", pszDirname, debug_v2_found ? "Debug V2" : "Debug"); } else { ret = sysfs_new_connection(ctx, conn, pszDirname, acpi); mxt_dbg(ctx, "Found %s", pszDirname); goto close; } } else { mxt_verb(ctx, "Ignoring %s", pszDirname); } ret = MXT_ERROR_NO_DEVICE; close: (void)closedir(pDirectory); free: free(pszDirname); return ret; }
//****************************************************************************** /// \brief Main bridge function to handle a single connection /// \return #mxt_rc static int bridge(struct mxt_device *mxt, int sockfd) { int ret, pollret; struct pollfd fds[2]; int fopts = 0; int debug_ng_fd = 0; int numfds = 1; int timeout; mxt_info(mxt->ctx, "Connected"); ret = mxt_msg_reset(mxt); if (ret) mxt_err(mxt->ctx, "Failure to reset msgs"); fds[0].fd = sockfd; fds[0].events = POLLIN | POLLERR; ret = send_chip_attach(mxt, sockfd); if (ret) return ret; while (1) { debug_ng_fd = mxt_get_msg_poll_fd(mxt); if (debug_ng_fd) { fds[1].fd = debug_ng_fd; fds[1].events = POLLPRI; numfds = 2; timeout = -1; } else { timeout = 100; // milliseconds } pollret = poll(fds, numfds, timeout); if (pollret == -1 && errno == EINTR) { mxt_dbg(mxt->ctx, "Interrupted"); continue; } else if (pollret == -1) { mxt_err(mxt->ctx, "Poll returned %d (%s)", errno, strerror(errno)); ret = mxt_errno_to_rc(errno); goto disconnect; } /* Detect socket disconnect */ if (fcntl(sockfd, F_GETFL, &fopts) < 0) { ret = MXT_SUCCESS; mxt_dbg(mxt->ctx, "Socket disconnected"); goto disconnect; } if (fds[0].revents) { ret = handle_cmd(mxt, sockfd); if (ret) { mxt_dbg(mxt->ctx, "handle_cmd returned %d", ret); goto disconnect; } } /* If timeout or msg poll fd event */ if (pollret == 0 || fds[1].revents) { ret = handle_messages(mxt, sockfd); if (ret) goto disconnect; } } disconnect: mxt_info(mxt->ctx, "Disconnected"); return ret; }
//****************************************************************************** /// \brief Write LENGTH /// \return #mxt_rc static int mxt_t68_write_length(struct t68_ctx *ctx, uint8_t length) { mxt_dbg(ctx->lc, "Writing LENGTH=%u", length); return mxt_write_register(ctx->mxt, &length, ctx->t68_addr + T68_LENGTH, 1); }
//****************************************************************************** /// \brief Initialise parameters and allocate buffers /// \return #mxt_rc int mxt_debug_dump_initialise(struct t37_ctx *ctx) { struct mxt_id_info *id = ctx->mxt->info.id; int ret; ret = get_objects_addr(ctx); if (ret) { mxt_err(ctx->lc, "Failed to get object information"); return ret; } mxt_dbg(ctx->lc, "t37_size: %d", ctx->t37_size); ctx->page_size = ctx->t37_size - 2; mxt_dbg(ctx->lc, "page_size: %d", ctx->page_size); switch (ctx->mode) { case DELTAS_MODE: case REFS_MODE: ctx->self_cap = false; if (id->family == 0xA0 && id->variant == 0x00) { /* mXT1386 data is formatted into stripes */ ctx->x_size = 27; ctx->y_size = id->matrix_y_size; ctx->data_values = 27 * ctx->y_size; ctx->passes = 3; ctx->pages_per_pass = 8; } else { ctx->x_size = id->matrix_x_size; ctx->y_size = id->matrix_y_size; ctx->data_values = ctx->x_size * ctx->y_size; ctx->passes = 1; ctx->pages_per_pass = (ctx->data_values*2 + (ctx->page_size - 1)) / ctx->page_size; } ctx->stripe_width = ctx->y_size / ctx->passes; mxt_dbg(ctx->lc, "stripe_width: %d", ctx->stripe_width); break; case SELF_CAP_SIGNALS: case SELF_CAP_DELTAS: case SELF_CAP_REFS: ctx->self_cap = true; if (id->family != 164) { mxt_err(ctx->lc, "Self cap data not available"); return MXT_ERROR_NOT_SUPPORTED; } if (ctx->t111_instances == 0) { mxt_err(ctx->lc, "T111 not found"); return MXT_ERROR_OBJECT_NOT_FOUND; } // read Ymax Y values, plus Ymax or 2Ymax X values ctx->passes = ctx->t111_instances; ctx->y_size = id->matrix_y_size; ctx->x_size = ctx->y_size * ((id->matrix_x_size > ctx->y_size) ? 2 : 1); ctx->data_values = (ctx->y_size + ctx->x_size) * ctx->passes; ctx->pages_per_pass = ((ctx->y_size + ctx->x_size)*sizeof(uint16_t) +(ctx->page_size - 1)) / ctx->page_size; break; case AST_DELTAS: case AST_REFS: ctx->self_cap = false; ctx->active_stylus = true; if (id->family != 164) { mxt_err(ctx->lc, "active stylus data not available"); return MXT_ERROR_NOT_SUPPORTED; } if (ctx->t107_instances == 0) { mxt_err(ctx->lc, "T107 not found"); return MXT_ERROR_OBJECT_NOT_FOUND; } // read Ymax Y values, plus Ymax or 2Ymax X values ctx->passes = ctx->t107_instances; ctx->y_size = 2 * id->matrix_y_size; // two scans per axis ctx->x_size = ctx->y_size * ((id->matrix_x_size > ctx->y_size) ? 2 : 1); ctx->data_values = (ctx->y_size + ctx->x_size) * ctx->passes; ctx->pages_per_pass = ((ctx->y_size + ctx->x_size)*sizeof(uint16_t) +(ctx->page_size - 1)) / ctx->page_size; break; default: mxt_err(ctx->lc, "Unsupported mode %02X", ctx->mode); return MXT_INTERNAL_ERROR; } mxt_dbg(ctx->lc, "passes: %d", ctx->passes); mxt_dbg(ctx->lc, "pages_per_pass: %d", ctx->pages_per_pass); mxt_dbg(ctx->lc, "x_size: %d", ctx->x_size); mxt_dbg(ctx->lc, "y_size: %d", ctx->y_size); mxt_dbg(ctx->lc, "data_values: %d", ctx->data_values); /* allocate t37 buffers */ ctx->t37_buf = (struct t37_diagnostic_data *)calloc(1, ctx->t37_size); if (!ctx->t37_buf) { mxt_err(ctx->lc, "calloc failure"); return MXT_ERROR_NO_MEM; } /* allocate data buffer */ ctx->data_buf = (uint16_t *)calloc(ctx->data_values, sizeof(uint16_t)); if (!ctx->data_buf) { mxt_err(ctx->lc, "calloc failure"); /* free other buffer in error path */ free(ctx->t37_buf); ctx->t37_buf = NULL; return MXT_ERROR_NO_MEM; } return MXT_SUCCESS; }
//****************************************************************************** /// \brief Read and deal with incoming command /// \return #mxt_rc static int handle_cmd(struct mxt_device *mxt, struct bridge_context *bridge_ctx) { int ret; uint16_t address; uint16_t count; struct mxt_buffer linebuf; char *line; int offset; ret = mxt_buf_init(&linebuf); if (ret) return ret; ret = readline(mxt, bridge_ctx->sockfd, &linebuf); if (ret) { mxt_dbg(mxt->ctx, "Error reading or peer closed socket"); goto free; } line = (char *)linebuf.data; if (strlen(line) == 0) { ret = MXT_SUCCESS; goto free; } mxt_verb(mxt->ctx, "%s", line); if (!strcmp(line, "SAT")) { mxt_info(mxt->ctx, "Server attached"); ret = MXT_SUCCESS; } else if (!strcmp(line, "SDT")) { mxt_info(mxt->ctx, "Server detached"); ret = MXT_SUCCESS; } else if (sscanf(line, "REA %" SCNu16 " %" SCNu16, &address, &count) == 2) { ret = bridge_rea_cmd(mxt, bridge_ctx, address, count); } else if (sscanf(line, "WRI %" SCNu16 "%n", &address, &offset) == 1) { /* skip space */ offset += 1; ret = bridge_wri_cmd(mxt, bridge_ctx, address, line + offset, strlen(line) - offset); } else if (sscanf(line, "RST %" SCNu16 "%n", &address, &offset) == 1) { ret = bridge_handle_reset(mxt, bridge_ctx, address); ret = MXT_SUCCESS; } else if (sscanf(line, "MSGCFG %" SCNu16 "%n", &address, &offset) == 1) { mxt_info(mxt->ctx, "Configuring Messages"); bridge_ctx->msgs_enabled = true; const char * const msg = "MSGCFG OK\n"; ret = write(bridge_ctx->sockfd, msg, strlen(msg)); if (ret < 0) { mxt_err(mxt->ctx, "Socket write error: %s (%d)", strerror(errno), errno); ret = mxt_errno_to_rc(errno); } ret = MXT_SUCCESS; } else { mxt_info(mxt->ctx, "Unrecognised cmd \"%s\"", line); ret = MXT_SUCCESS; } free: mxt_buf_free(&linebuf); return ret; }