#include <linux/slab.h>
#include <linux/firmware.h>
-#define IGNORE_CHECKSUM_MISMATCH
-
struct qtm_object {
struct qtm_obj_entry entry;
uint8_t report_id_min;
unsigned long obj_map[_BITMAP_LEN];
uint32_t last_keystate;
- uint16_t eeprom_checksum;
+ uint32_t eeprom_checksum;
uint8_t checksum_cnt;
int x_delta;
int y_delta;
return 0;
}
+static uint32_t crc24(uint32_t crc, uint8_t first_byte, uint8_t sec_byte)
+{
+ static const uint32_t crcpoly = 0x80001b;
+ uint32_t result = 0;
+ uint16_t data_word = 0;
+
+ data_word = (uint16_t)((uint16_t)(sec_byte << 8u) | first_byte);
+ result = ((crc<<1u) ^ (uint32_t)data_word);
+ /* If bit 25 is set, XOR result with crcpoly */
+ if (result & 0x1000000)
+ result ^= crcpoly;
+
+ return result;
+}
-static uint16_t calc_csum(uint16_t curr_sum, void *_buf, int buf_sz)
+static uint32_t calc_csum(uint32_t curr_sum, void *_buf, int buf_sz)
{
uint8_t *buf = _buf;
- uint32_t new_sum;
- int i;
+ int i = 0;
+ int odd = 0;
- while (buf_sz-- > 0) {
- new_sum = (((uint32_t) curr_sum) << 8) | *(buf++);
- for (i = 0; i < 8; ++i) {
- if (new_sum & 0x800000)
- new_sum ^= 0x800500;
- new_sum <<= 1;
- }
- curr_sum = ((uint32_t) new_sum >> 8) & 0xffff;
+ if (buf_sz % 2) {
+ buf_sz -= 1;
+ odd = 1;
}
+ while (i < buf_sz) {
+ curr_sum = crc24(curr_sum, *(buf + i), *(buf + i + 1));
+ i += 2;
+ }
+ if (odd)
+ curr_sum = crc24(curr_sum, *(buf + i), 0);
+ /* Final Result */
+ curr_sum = (curr_sum & 0x00FFFFFF);
return curr_sum;
}
struct qtm_cmd_proc_msg *msg = _msg;
int ret = 0;
int hw_reset = 0;
+ uint32_t checksum = (msg->checksum[2] << 16)
+ | (msg->checksum[1] << 8) | msg->checksum[0];
if (msg->status & QTM_CMD_PROC_STATUS_RESET) {
if (qtouch_tsdebug)
pr_info("%s:EEPROM checksum is 0x%X cnt %i\n",
- __func__, msg->checksum, ts->checksum_cnt);
- if (msg->checksum != ts->eeprom_checksum) {
+ __func__, checksum, ts->checksum_cnt);
+ if (checksum != ts->eeprom_checksum) {
if (ts->checksum_cnt > 2) {
/* Assume the checksum is what it is, cannot
disable the touch screen so set the checksum*/
- ts->eeprom_checksum = msg->checksum;
+ ts->eeprom_checksum = checksum;
ts->checksum_cnt = 0;
} else {
pr_info("%s:EEPROM checksum doesn't match 0x%x\n",
- __func__, msg->checksum);
+ __func__, checksum);
ret = qtouch_hw_init(ts);
if (ret != 0)
pr_err("%s:Cannot init the touch IC\n",
the checksum to change during operation so we need to
reprogram the EEPROM and reset the IC */
if (ts->pdata->flags & QTOUCH_EEPROM_CHECKSUM) {
- if (msg->checksum != ts->eeprom_checksum) {
+ if (checksum != ts->eeprom_checksum) {
if (qtouch_tsdebug)
pr_info("%s:EEPROM checksum is 0x%X cnt %i\n",
- __func__, msg->checksum,
+ __func__, checksum,
ts->checksum_cnt);
if (ts->checksum_cnt > 2) {
/* Assume the checksum is what it is, cannot
disable the touch screen so set the checksum*/
- ts->eeprom_checksum = msg->checksum;
+ ts->eeprom_checksum = checksum;
ts->checksum_cnt = 0;
} else {
if (!hw_reset) {
err = request_firmware(&fw_entry, ts->pdata->touch_fw_cfg.fw_name,
&ts->client->dev);
- if ( err == 0) {
+ if (err == 0) {
ts->touch_fw = (uint8_t *)fw_entry->data;
ts->touch_fw_size = fw_entry->size;
pr_info("firmware name: %s size: %d\n", ts->touch_fw_image,
static int qtouch_process_info_block(struct qtouch_ts_data *ts)
{
struct qtm_id_info qtm_info;
- uint16_t our_csum = 0x0;
- uint16_t their_csum;
+ uint32_t our_csum = 0x0;
+ uint32_t their_csum;
uint8_t report_id;
uint16_t addr;
int err;
int i;
- unsigned char powerconfig[5];
-
- /* HACK!!: This is a hack
- Once we have a new load of firmware we MUST remove this */
- powerconfig[0] = 0x35;
- powerconfig[1] = 0x01;
- powerconfig[2] = 0x0a;
- powerconfig[3] = 0x0a;
- powerconfig[4] = 0x01;
-
- err = qtouch_write(ts, powerconfig, 5);
- /* End Hack */
+ uint8_t *info_blk_buf, *info_blk_start;
+ uint16_t info_blk_size;
+ struct qtm_obj_entry entry;
+
/* query the device and get the info block. */
err = qtouch_read_addr(ts, QTM_OBP_ID_INFO_ADDR, &qtm_info,
sizeof(qtm_info));
pr_err("%s: Cannot read info object block\n", __func__);
goto err_read_info_block;
}
- our_csum = calc_csum(our_csum, &qtm_info, sizeof(qtm_info));
- /* TODO: Add a version/family/variant check? */
pr_info("%s: Build version is 0x%x\n", __func__, qtm_info.version);
if (qtm_info.num_objs == 0) {
goto err_no_objects;
}
+ info_blk_size = sizeof(qtm_info) + qtm_info.num_objs * sizeof(entry);
+ info_blk_buf = kzalloc(info_blk_size, GFP_KERNEL);
+ if (info_blk_buf == NULL) {
+ pr_err("%s: Can't allocate write buffer (%d)\n",
+ __func__, info_blk_size);
+ err = -ENOMEM;
+ goto err_no_objects;
+ }
+ info_blk_start = info_blk_buf;
+ memcpy(info_blk_buf, (void *)&qtm_info, sizeof(qtm_info));
+ info_blk_buf += sizeof(qtm_info);
addr = QTM_OBP_ID_INFO_ADDR + sizeof(qtm_info);
report_id = 1;
/* read out the object entries table */
for (i = 0; i < qtm_info.num_objs; ++i) {
struct qtm_object *obj;
- struct qtm_obj_entry entry;
pr_info("%s: Reading addr: %i\n", __func__, addr);
err = qtouch_read_addr(ts, addr, &entry, sizeof(entry));
err = -EIO;
goto err_read_entry;
}
- our_csum = calc_csum(our_csum, &entry, sizeof(entry));
+
+ memcpy(info_blk_buf, (void *)&entry, sizeof(entry));
+ info_blk_buf += sizeof(entry);
addr += sizeof(entry);
entry.size++;
ts->msg_size = entry.size;
entry.addr |= QTOUCH_USE_MSG_CRC_MASK;
} else {
- ts->msg_size = entry.size -1;
+ ts->msg_size = entry.size - 1;
}
}
goto err_no_checksum;
}
- /* FIXME: The algorithm described in the datasheet doesn't seem to
- * match what the touch firmware is doing on the other side. We
- * always get mismatches! */
+ our_csum = calc_csum(our_csum, info_blk_start, info_blk_size);
+
if (our_csum != their_csum) {
- pr_warning("%s: Checksum mismatch (0x%04x != 0x%04x)\n",
+ pr_warning("%s: Checksum mismatch (0x%08x != 0x%08x)\n",
__func__, our_csum, their_csum);
#ifndef IGNORE_CHECKSUM_MISMATCH
err = -ENODEV;
#endif
}
- pr_info("%s: %s found. family 0x%x, variant 0x%x, ver 0x%x, "
- "build 0x%x, matrix %dx%d, %d objects.\n", __func__,
+ pr_info("%s: %s found.\n family 0x%x, variant 0x%x, ver 0x%x\n"
+ " build 0x%x, matrix %dx%d, %d objects.\n", __func__,
QTOUCH_TS_NAME, qtm_info.family_id, qtm_info.variant_id,
qtm_info.version, qtm_info.build, qtm_info.matrix_x_size,
qtm_info.matrix_y_size, qtm_info.num_objs);
ts->variant_id = qtm_info.variant_id;
ts->fw_version = qtm_info.version;
ts->build_version = qtm_info.build;
+ kfree(info_blk_start);
return 0;
+err_bad_checksum:
err_no_checksum:
err_missing_objs:
err_no_msg_proc:
err_read_entry:
+ kfree(info_blk_start);
err_no_objects:
err_read_info_block:
return err;
enable_irq(ts->client->irq);
}
- /* HACK!! Don't put the touch to sleep. This
- must be removed after we get new firmware
ret = qtouch_power_config(ts, 0);
if (ret < 0)
- pr_err("%s: Cannot write power config\n", __func__);*/
+ pr_err("%s: Cannot write power config\n", __func__);
return 0;
}