//****************************************************************************** /// \brief Read MXT messages and send them to other end /// \return #mxt_rc static int handle_messages(struct mxt_device *mxt, int sockfd) { int count, i; char *msg; int ret; ret = mxt_get_msg_count(mxt, &count); if (ret) return ret; if (count > 0) { for (i = 0; i < count; i++) { msg = mxt_get_msg_string(mxt); if (msg == NULL) { mxt_warn(mxt->ctx, "Failed to retrieve message"); return MXT_SUCCESS; } ret = write(sockfd, msg, strlen(msg)); if (ret < 0) { mxt_err(mxt->ctx, "Write failure: %s (%d)", strerror(errno), errno); return mxt_errno_to_rc(ret); } ret = write(sockfd, "\n", 1); if (ret < 0) { mxt_err(mxt->ctx, "Write failure: %s (%d)", strerror(errno), errno); return mxt_errno_to_rc(ret); } } } return MXT_SUCCESS; }
//****************************************************************************** /// \brief Get messages (V2 interface) /// \param mxt Device context /// \param count Number of messages retrieved /// \return #mxt_rc int sysfs_get_msgs_v2(struct mxt_device *mxt, int *count) { int num_bytes; uint16_t t5_size; char *filename; struct stat filestat; int ret; int fd; sysfs_reopen_notify_fd(mxt); filename = make_path(mxt, "debug_msg"); ret = stat(filename, &filestat); if (ret < 0) { mxt_err(mxt->ctx, "Could not stat %s, error %s (%d)", filename, strerror(errno), errno); return mxt_errno_to_rc(errno); } mxt->sysfs.debug_v2_size = filestat.st_size; if (mxt->sysfs.debug_v2_msg_buf) { free(mxt->sysfs.debug_v2_msg_buf); mxt->sysfs.debug_v2_msg_buf = NULL; } mxt->sysfs.debug_v2_msg_buf = calloc(mxt->sysfs.debug_v2_size, sizeof(uint8_t)); fd = open(filename, O_RDWR); if (fd < 0) { mxt_err(mxt->ctx, "Could not open %s, error %s (%d)", filename, strerror(errno), errno); ret = mxt_errno_to_rc(errno); goto close; } t5_size = mxt_get_object_size(mxt, GEN_MESSAGEPROCESSOR_T5) - 1; num_bytes = read(fd, mxt->sysfs.debug_v2_msg_buf, mxt->sysfs.debug_v2_size); if (num_bytes < 0) { mxt_err(mxt->ctx, "read error %s (%d)", strerror(errno), errno); ret = mxt_errno_to_rc(errno); goto close; } mxt->sysfs.debug_v2_msg_count = num_bytes / t5_size; mxt->sysfs.debug_v2_msg_ptr = 0; ret = MXT_SUCCESS; *count = mxt->sysfs.debug_v2_msg_count; mxt_verb(mxt->ctx, "count = %d", mxt->sysfs.debug_v2_msg_count); close: close(fd); return ret; }
//****************************************************************************** /// \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 Get system uptime in seconds since boot int get_uptime(unsigned long *uptime) { FILE *fp; int ret; unsigned long upsecs; char buf[64]; char *b; fp = fopen("/proc/uptime", "r"); if (!fp) return mxt_errno_to_rc(errno); b = fgets(buf, BUFSIZ, fp); if (b == buf) { /* The following sscanf must use the C locale. */ setlocale(LC_NUMERIC, "C"); ret = sscanf(buf, "%lf", &upsecs); setlocale(LC_NUMERIC, ""); if (ret == 1) { *uptime = upsecs; ret = MXT_SUCCESS; } } else { ret = MXT_ERROR_IO; } fclose(fp); return ret; }
//****************************************************************************** /// \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 Read boolean from file as ASCII 0/1 /// \param mxt Device context /// \param filename Name of file to read /// \param value Value read from file /// \return #mxt_rc static int read_boolean_file(struct mxt_device *mxt, char *filename, bool *value) { FILE *file; char val; bool ret; file = fopen(filename, "r"); if (!file) { mxt_err(mxt->ctx, "Could not open %s, error %s (%d)", filename, strerror(errno), errno); return mxt_errno_to_rc(errno); } ret = fread(&val, sizeof(char), 1, file); if (ret < 0) { mxt_err(mxt->ctx, "Error reading files"); return MXT_ERROR_IO; } if (val == 49) { // ASCII '0' *value = true; } else { *value = false; } fclose(file); return MXT_SUCCESS; }
//****************************************************************************** /// \brief Read MXT messages and send them to other end /// \return #mxt_rc static int handle_messages(struct mxt_device *mxt, struct bridge_context *bridge_ctx) { int msg_count, length; int ret; int i, j; unsigned char databuf[20]; if (!bridge_ctx->msgs_enabled) return MXT_SUCCESS; ret = mxt_get_msg_count(mxt, &msg_count); if (ret) return ret; for (i = 0; i < msg_count; i++) { int num_bytes; ret = mxt_get_msg_bytes(mxt, databuf, sizeof(databuf), &num_bytes); if (ret == MXT_ERROR_NO_MESSAGE) continue; else if (ret) return ret; length = snprintf(mxt->msg_string, sizeof(mxt->msg_string), MXT_ADB_CLIENT_MSG_PREFIX); for (j = 0; j < num_bytes; j++) { length += snprintf(mxt->msg_string + length, sizeof(mxt->msg_string) - length, "%02X", databuf[j]); } ret = write(bridge_ctx->sockfd, mxt->msg_string, strlen(mxt->msg_string)); if (ret < 0) { mxt_err(mxt->ctx, "Write failure: %s (%d)", strerror(errno), errno); return mxt_errno_to_rc(ret); } ret = write(bridge_ctx->sockfd, "\n", 1); if (ret < 0) { mxt_err(mxt->ctx, "Write failure: %s (%d)", strerror(errno), errno); return mxt_errno_to_rc(ret); } } return MXT_SUCCESS; }
//****************************************************************************** /// \brief Handle bridge read /// \return #mxt_rc static int bridge_rea_cmd(struct mxt_device *mxt, int sockfd, uint16_t address, uint16_t count) { int ret; uint8_t *databuf; char *response; const char * const PREFIX = "RRP "; size_t response_len; int i; databuf = calloc(count, sizeof(uint8_t)); if (!databuf) { mxt_err(mxt->ctx, "Failed to allocate memory"); return MXT_ERROR_NO_MEM; } /* Allow for newline/null byte */ response_len = strlen(PREFIX) + count*2 + 1; response = calloc(response_len, sizeof(uint8_t)); if (!response) { mxt_err(mxt->ctx, "Failed to allocate memory"); ret = MXT_ERROR_NO_MEM; goto free_databuf; } strcpy(response, PREFIX); ret = mxt_read_register(mxt, databuf, address, count); if (ret) { mxt_warn(mxt->ctx, "RRP ERR"); strcpy(response + strlen(PREFIX), "ERR\n"); response_len = strlen(response); } else { for (i = 0; i < count; i++) { sprintf(response + strlen(PREFIX) + i*2, "%02X", databuf[i]); } mxt_info(mxt->ctx, "%s", response); response[response_len - 1] = '\n'; } ret = write(sockfd, response, response_len); if (ret < 0) { mxt_err(mxt->ctx, "Socket write error: %s (%d)", strerror(errno), errno); ret = mxt_errno_to_rc(errno); goto free; } ret = MXT_SUCCESS; free: free(response); free_databuf: free(databuf); return ret; }
//****************************************************************************** /// \brief Allocate kernel log buffer int dmesg_alloc_buffer(struct mxt_device *mxt) { int size; size = klogctl(SYSLOG_ACTION_SIZE_BUFFER, NULL, 0); if (size == -1) { mxt_err(mxt->ctx, "klogctl error %d (%s)", errno, strerror(errno)); return mxt_errno_to_rc(errno); } // Allocate buffer space mxt->sysfs.debug_msg_buf_size = size; mxt->sysfs.debug_msg_buf = (char *)calloc(size, sizeof(char)); if (mxt->sysfs.debug_msg_buf == NULL) { mxt_err(mxt->ctx, "Error allocating debug_msg_buf"); return mxt_errno_to_rc(errno); } return 0; }
//****************************************************************************** /// \brief Get system uptime in seconds since boot /// \return #mxt_rc int get_uptime(unsigned long *uptime) { int ret; struct sysinfo sys_info; ret = sysinfo(&sys_info); if (ret) return mxt_errno_to_rc(errno); *uptime = sys_info.uptime; return MXT_SUCCESS; }
//****************************************************************************** /// \brief Open sysfs MSG notify attribute /// \return #mxt_rc static int sysfs_open_notify_fd(struct mxt_device *mxt) { char *filename = make_path(mxt, "debug_notify"); mxt->sysfs.debug_notify_fd = open(filename, O_RDONLY); if (mxt->sysfs.debug_notify_fd < 0) { mxt_err(mxt->ctx, "Could not open %s, error %s (%d)", filename, strerror(errno), errno); return mxt_errno_to_rc(errno); } return MXT_SUCCESS; }
//****************************************************************************** /// \brief Send chip attach message /// \return #mxt_rc static int send_chip_attach(struct mxt_device *mxt, int sockfd) { int ret; const char * const msg = "CAT\n"; ret = write(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); } return MXT_SUCCESS; }
//****************************************************************************** /// \brief Write register to MXT chip /// \return #mxt_rc int sysfs_write_register(struct mxt_device *mxt, unsigned char const *buf, int start_register, size_t count) { int fd = -ENODEV; int ret; size_t bytes_written; ret = open_device_file(mxt, &fd); if (ret) return ret; if (lseek(fd, start_register, 0) < 0) { mxt_err(mxt->ctx, "lseek error %s (%d)", strerror(errno), errno); ret = mxt_errno_to_rc(errno); goto close; } bytes_written = 0; while (bytes_written < count) { ret = write(fd, buf+bytes_written, count - bytes_written); if (ret == 0) { ret = MXT_ERROR_IO; goto close; } else if (ret < 0) { mxt_err(mxt->ctx, "Error %s (%d) writing to register", strerror(errno), errno); ret = mxt_errno_to_rc(errno); goto close; } bytes_written += ret; } ret = MXT_SUCCESS; close: close(fd); return ret; }
//****************************************************************************** /// \brief Send chip detach message /// \return #mxt_rc static int send_chip_detach(struct mxt_device *mxt, struct bridge_context *bridge_ctx) { int ret; const char * const msg = "CDT\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); } return MXT_SUCCESS; }
//****************************************************************************** /// \brief Read register from MXT chip /// \return #mxt_rc int sysfs_read_register(struct mxt_device *mxt, unsigned char *buf, int start_register, size_t count, size_t *bytes_read) { int fd = -ENODEV; int ret; ret = open_device_file(mxt, &fd); if (ret) return ret; if (lseek(fd, start_register, 0) < 0) { mxt_err(mxt->ctx, "lseek error %s (%d)", strerror(errno), errno); ret = mxt_errno_to_rc(errno); goto close; } *bytes_read = 0; while (*bytes_read < count) { ret = read(fd, buf + *bytes_read, count - *bytes_read); if (ret == 0) { ret = MXT_ERROR_IO; goto close; } else if (ret < 0) { mxt_err(mxt->ctx, "read error %s (%d)", strerror(errno), errno); ret = mxt_errno_to_rc(errno); goto close; } *bytes_read += ret; } ret = MXT_SUCCESS; close: close(fd); return ret; }
//****************************************************************************** /// \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 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 Set debug state /// \param mxt Device context /// \param debug_state true = debug enabled, false = debug disabled /// \return #mxt_rc int sysfs_set_debug(struct mxt_device *mxt, bool debug_state) { int ret; // Check device is initialised if (!mxt) { mxt_err(mxt->ctx, "Device uninitialised"); return MXT_ERROR_NO_DEVICE; } if (mxt->sysfs.debug_v2 == true) { ret = write_boolean_file(mxt, make_path(mxt, "debug_v2_enable"), debug_state); if (ret) ret = write_boolean_file(mxt, make_path(mxt, "debug_enable"), debug_state); if (debug_state) { ret = sysfs_open_notify_fd(mxt); if (ret) return ret; } else { close(mxt->sysfs.debug_notify_fd); } } else { ret = MXT_SUCCESS; if (debug_state) { // Allocate buffer space mxt->sysfs.debug_msg_buf_size = dmesg_buf_size(); mxt->sysfs.debug_msg_buf = (char *)calloc(mxt->sysfs.debug_msg_buf_size, sizeof(char)); if (mxt->sysfs.debug_msg_buf == NULL) { mxt_err(mxt->ctx, "Error allocating memory for debug_msg_buf_size"); ret = mxt_errno_to_rc(errno); } } else if (mxt->sysfs.debug_msg_buf) { // Free up the message buffer free(mxt->sysfs.debug_msg_buf); mxt->sysfs.debug_msg_buf = NULL; } if (ret == MXT_SUCCESS) ret = write_boolean_file(mxt, make_path(mxt, "debug_enable"), debug_state); } return ret; }
//****************************************************************************** /// \brief Handle bridge reset command /// \return #mxt_rc static int bridge_handle_reset(struct mxt_device *mxt, struct bridge_context *bridge_ctx, uint16_t address) { int ret; char *response; const char * const PREFIX = "RST "; size_t response_len = 8; /* Allow for newline/null byte */ response = calloc(response_len, sizeof(uint8_t)); if (!response) { mxt_err(mxt->ctx, "Failed to allocate memory"); ret = MXT_ERROR_NO_MEM; goto free; } strcpy(response, PREFIX); ret = mxt_reset_chip(mxt, false); if (ret) { mxt_warn(mxt->ctx, "RST ERR"); strcpy(response + strlen(PREFIX), "ERR\n"); response_len = strlen(response); } else { mxt_info(mxt->ctx, "RST OK"); strcpy(response + strlen(PREFIX), "OK\n"); response_len = strlen(response); } ret = write(bridge_ctx->sockfd, response, response_len); if (ret < 0) { mxt_err(mxt->ctx, "Socket write error: %s (%d)", strerror(errno), errno); ret = mxt_errno_to_rc(errno); goto free; } ret = MXT_SUCCESS; free: free(response); return ret; }
//****************************************************************************** /// \brief Open device /// \return #mxt_rc int sysfs_open(struct mxt_device *mxt) { struct sysfs_conn_info *conn = &mxt->conn->sysfs; char *filename; struct stat filestat; int ret; mxt->sysfs.path_max = strlen(conn->path) + 20; // Allocate temporary path space mxt->sysfs.temp_path = calloc(mxt->sysfs.path_max + 1, sizeof(char)); if (!mxt->sysfs.temp_path) return MXT_ERROR_NO_MEM; // Cache memory access path for fast access mxt->sysfs.mem_access_path = calloc(mxt->sysfs.path_max + 1, sizeof(char)); if (!mxt->sysfs.mem_access_path) return MXT_ERROR_NO_MEM; snprintf(mxt->sysfs.mem_access_path, mxt->sysfs.path_max, "%s/mem_access", conn->path); // Check whether debug v2 or not filename = make_path(mxt, "debug_msg"); ret = stat(filename, &filestat); if (ret < 0) { if (errno == ENOENT) { mxt->sysfs.debug_v2 = false; } else { mxt_err(mxt->ctx, "Could not stat %s, error %s (%d)", filename, strerror(errno), errno); return mxt_errno_to_rc(errno); } } else { mxt->sysfs.debug_v2 = true; } mxt_info(mxt->ctx, "Registered sysfs path:%s", conn->path); return MXT_SUCCESS; }
//****************************************************************************** /// \brief Write boolean to file as ASCII 0/1 /// \param mxt Device context /// \param filename Name of file to write /// \param value Value to write /// \return #mxt_rc static int write_boolean_file(struct mxt_device *mxt, const char *filename, bool value) { FILE *file; file = fopen(filename, "w+"); if (!file) { mxt_err(mxt->ctx, "Could not open %s, error %s (%d)", filename, strerror(errno), errno); return mxt_errno_to_rc(errno); } if (value == true) { fputs("1", file); } else { fputs("0", file); } fclose(file); return MXT_SUCCESS; }
//****************************************************************************** /// \brief Open memory access file /// \return #mxt_rc static int open_device_file(struct mxt_device *mxt, int *fd_out) { int fd; // Check device is initialised if (!mxt || !mxt->sysfs.mem_access_path) { mxt_err(mxt->ctx, "Device uninitialised"); return MXT_ERROR_NO_DEVICE; } fd = open(mxt->sysfs.mem_access_path, O_RDWR); if (fd < 0) { mxt_err(mxt->ctx, "Could not open %s, error %s (%d)", mxt->sysfs.mem_access_path, strerror(errno), errno); return mxt_errno_to_rc(errno); } *fd_out = fd; return MXT_SUCCESS; }
//****************************************************************************** /// \brief Handle bridge write /// \return #mxt_rc static int bridge_wri_cmd(struct mxt_device *mxt, int sockfd, uint16_t address, char *hex, uint16_t bytes) { int ret; uint16_t count; const char * const FAIL = "WRP ERR\n"; const char * const PASS = "******"; const char *response; uint8_t *databuf; databuf = calloc(bytes, sizeof(uint8_t)); if (!databuf) { mxt_err(mxt->ctx, "Failed to allocate memory"); return MXT_ERROR_NO_MEM; } ret = mxt_convert_hex(hex, databuf, &count, bytes); if (ret) { response = FAIL; } else { ret = mxt_write_register(mxt, databuf, address, count); if (ret) { mxt_verb(mxt->ctx, "WRI OK"); response = FAIL; } else { response = PASS; } } ret = write(sockfd, response, strlen(response)); if (ret < 0) { mxt_err(mxt->ctx, "Socket write error: %s (%d)", strerror(errno), errno); ret = mxt_errno_to_rc(errno); } ret = MXT_SUCCESS; free(databuf); return ret; }
//****************************************************************************** /// \brief Read command on a single line /// \return #mxt_rc static int readline(struct mxt_device *mxt, int fd, struct mxt_buffer *linebuf) { int ret; int n; int readcount; char c; mxt_buf_reset(linebuf); for (n = 1; n < MAX_LINESIZE; n++) { /* read 1 character at a time */ readcount = read(fd, &c, 1); if (readcount == 1) { if ((c == '\n') || (c == '\r')) break; ret = mxt_buf_add(linebuf, c); if (ret) return ret; } else if (readcount == 0) { if (n == 1) return MXT_SUCCESS; else break; } else { mxt_err(mxt->ctx, "Read error: %s (%d)", strerror(errno), errno); return mxt_errno_to_rc(errno); } } /* null-terminate the buffer */ ret = mxt_buf_add(linebuf, '\0'); if (ret) return ret; return MXT_SUCCESS; }
//****************************************************************************** /// \brief Read hex encoded data from file /// \return #mxt_rc static int mxt_t68_load_file(struct t68_ctx *ctx) { int ret; uint8_t value = 0; FILE *fp; bool file_read = false; char buf[256]; uint16_t hexcount; int c; /* open file */ fp = fopen(ctx->filename, "r"); if (fp == NULL) { mxt_err(ctx->lc, "Error opening %s", ctx->filename); return mxt_errno_to_rc(errno); } ret = mxt_buf_init(&ctx->buf); if (ret) { mxt_err(ctx->lc, "Error initialising buffer"); goto close; } while (!file_read) { /* Read next value from file */ c = getc(fp); if (c == EOF) { break; } /* skip spaces, newlines, commas*/ else if (c == 0x20 || c == '\r' || c == '\n' || c == ',') { continue; } /* Ignore comment lines */ else if (c == '[') { // Grab comment key if (fscanf(fp, "%255[^]]", buf) != 1) { ret = MXT_ERROR_FILE_FORMAT; goto fail; } mxt_verb(ctx->lc, "[%s]", buf); if (!strncasecmp(buf, "datatype=", 9)) { if (sscanf(buf + 9, "%d", &c) != 1) { mxt_warn(ctx->lc, "Unable to parse datatype"); } else { ctx->t68_datatype = c; mxt_info(ctx->lc, "DATATYPE set to %u by file", ctx->t68_datatype); } } // Read until end of line while (c != '\n') { c = getc(fp); } continue; } /* A value looks like "0xABu," */ else if (c == '0') { if (fscanf(fp, "x%2su", (char *)&buf) != 1) { mxt_err(ctx->lc, "Parse error"); ret = MXT_ERROR_FILE_FORMAT; goto fail; } ret = mxt_convert_hex(buf, &value, &hexcount, 3); if (ret) goto fail; ret = mxt_buf_add(&ctx->buf, value); if (ret) goto fail; } else { mxt_err(ctx->lc, "Unexpected character \"%c\"", c); ret = MXT_ERROR_FILE_FORMAT; goto fail; } } mxt_info(ctx->lc, "Loaded file %s, %zu bytes", ctx->filename, ctx->buf.size); return MXT_SUCCESS; fail: mxt_buf_free(&ctx->buf); close: fclose(fp); return ret; }
//****************************************************************************** /// \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; }
//****************************************************************************** /// \brief Get messages /// \param mxt Maxtouch Device /// \param count Number of messages available /// \param init_timestamp Read newest dmesg line and initialise timestamp /// \return #mxt_rc int dmesg_get_msgs(struct mxt_device *mxt, int *count, bool init_timestamp) { char msg[BUFFERSIZE]; int ep, sp; int ret = MXT_SUCCESS; unsigned long sec, msec, lastsec = 0, lastmsec = 0; // Read entire kernel log buffer ep = klogctl(SYSLOG_ACTION_READ_ALL, mxt->sysfs.debug_msg_buf, mxt->sysfs.debug_msg_buf_size); // Return if no bytes read if (ep < 0) { mxt_warn(mxt->ctx, "klogctl error %d (%s)", errno, strerror(errno)); ret = mxt_errno_to_rc(errno); } else { // null terminate mxt->sysfs.debug_msg_buf[ep] = 0; sp = ep; if (!init_timestamp) dmesg_list_empty(mxt); // Search for next new line character while (true) { sp--; while (sp >= 0 && *(mxt->sysfs.debug_msg_buf + sp) != '\n') sp--; if (sp <= 0) break; // Try to parse dmesg line if (sscanf(mxt->sysfs.debug_msg_buf+sp+1, "< %*c>[ %lu.%06lu] %255[^\n]", &sec, &msec, msg) == 3) { if (init_timestamp) { mxt->sysfs.timestamp = sec; mxt->sysfs.mtimestamp = msec; mxt_verb(mxt->ctx, "%s - init [%5lu.%06lu]", __func__, sec, msec); break; } // Store time of last message in buffer if (lastsec == 0) { lastsec = sec; lastmsec = msec; } // Only 500 at a time, otherwise we overrun JNI reference limit. // Timestamp must be greater than previous messages, slightly // complicated by seconds and microseconds if ((mxt->sysfs.dmesg_count > MAX_DMESG_COUNT) || (sec == mxt->sysfs.timestamp && msec <= mxt->sysfs.mtimestamp) || (sec < mxt->sysfs.timestamp)) { mxt->sysfs.timestamp = lastsec; mxt->sysfs.mtimestamp = lastmsec; break; } char* msgptr; msg[sizeof(msg) - 1] = '\0'; msgptr = strstr(msg, "MXT MSG"); if (msgptr) dmesg_list_add(mxt, sec, msec, msgptr); } } if (!init_timestamp) { *count = mxt->sysfs.dmesg_count; mxt->sysfs.dmesg_ptr = mxt->sysfs.dmesg_head; } } 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; }