コード例 #1
0
int flash_query(struct wacom_i2c *wac_i2c)
{
	u8 command[CMD_SIZE];
	u8 response[RSP_SIZE];
	int ret, ECH;
	int len = 0;

	command[len++] = 4;	/* Command Register-LSB */
	command[len++] = 0;	/* Command Register-MSB */
	command[len++] = 0x37;	/* Command-LSB, ReportType:Feature(11) ReportID:7 */
	command[len++] = CMD_SET_FEATURE;	/* Command-MSB, SET_REPORT */
	command[len++] = 5;	/* Data Register-LSB */
	command[len++] = 0;	/* Data-Register-MSB */
	command[len++] = 5;	/* Length Field-LSB */
	command[len++] = 0;	/* Length Field-MSB */
	command[len++] = BOOT_CMD_REPORT_ID;	/* Report:ReportID */
	command[len++] = BOOT_QUERY;	/* Report:Boot Query command */
	command[len++] = ECH = 7;	/* Report:echo */

	ret = wacom_i2c_send(wac_i2c, command, len, WACOM_I2C_MODE_BOOT);
	if (ret < 0) {
		printk(KERN_DEBUG"epen:%s 2 ret:%d \n", __func__, ret);
		return -EXIT_FAIL_SEND_QUERY_COMMAND;
	}

	len = 0;
	command[len++] = 4;	/* Command Register-LSB */
	command[len++] = 0;	/* Command Register-MSB */
	command[len++] = 0x38;	/* Command-LSB, ReportType:Feature(11) ReportID:8 */
	command[len++] = CMD_GET_FEATURE;	/* Command-MSB, GET_REPORT */
	command[len++] = 5;	/* Data Register-LSB */
	command[len++] = 0;	/* Data Register-MSB */

	ret = wacom_i2c_send(wac_i2c, command, len, WACOM_I2C_MODE_BOOT);
	if (ret < 0) {
		printk(KERN_DEBUG"epen:%s 2 ret:%d \n", __func__, ret);
		return -EXIT_FAIL_SEND_QUERY_COMMAND;
	}

	msleep(10);

	ret = wacom_i2c_recv(wac_i2c, response, BOOT_RSP_SIZE,
			     WACOM_I2C_MODE_BOOT);
	if (ret < 0) {
		printk(KERN_DEBUG"epen:%s 5 ret:%d \n", __func__, ret);
		return -EXIT_FAIL_SEND_QUERY_COMMAND;
	}

	if ((response[3] != QUERY_CMD) || (response[4] != ECH)) {
		printk(KERN_DEBUG"epen:%s res3:%x res4:%x \n", __func__, response[3],
		       response[4]);
		return -EXIT_FAIL_SEND_QUERY_COMMAND;
	}
	if (response[5] != QUERY_RSP) {
		printk(KERN_DEBUG"epen:%s res5:%x \n", __func__, response[5]);
		return -EXIT_FAIL_SEND_QUERY_COMMAND;
	}

	return 0;
}
コード例 #2
0
int wacom_i2c_test(struct wacom_i2c *wac_i2c)
{
	int ret, i;
	char buf, test[10];
	buf = COM_QUERY;

	ret = wacom_i2c_send(wac_i2c, &buf, sizeof(buf), false);
	if (ret > 0)
		printk(KERN_INFO "[E-PEN] buf:%d, sent:%d\n", buf, ret);
	else {
		printk(KERN_ERR "[E-PEN] Digitizer is not active\n");
		return -1;
	}

	ret = wacom_i2c_recv(wac_i2c, test, sizeof(test), false);
	if (ret >= 0) {
		for (i = 0; i < 8; i++)
			printk(KERN_INFO "[E-PEN] %d\n", test[i]);
	} else {
		printk(KERN_ERR "[E-PEN] Digitizer does not reply\n");
		return -1;
	}

	return 0;
}
コード例 #3
0
static void wacom_open_test(struct wacom_i2c *wac_i2c)
{
	u8 cmd = 0;
	u8 buf[2] = {0,};
	int ret = 0, cnt = 30;

	cmd = WACOM_I2C_STOP;
	ret = wacom_i2c_send(wac_i2c, &cmd, 1, false);
	if (ret <= 0) {
		printk(KERN_ERR "[E-PEN] failed to send stop command\n");
		return ;
	}

	cmd = WACOM_I2C_GRID_CHECK;
	ret = wacom_i2c_send(wac_i2c, &cmd, 1, false);
	if (ret <= 0) {
		printk(KERN_ERR "[E-PEN] failed to send stop command\n");
		goto grid_check_error;
	}

	cmd = WACOM_STATUS;
	do {
		msleep(50);
		if (1 == wacom_i2c_send(wac_i2c, &cmd, 1, false)) {
			if (2 == wacom_i2c_recv(wac_i2c,
						buf, 2, false)) {
				switch (buf[0]) {
				/*
				*	status value
				*	0 : data is not ready
				*	1 : PASS
				*	2 : Fail (coil function error)
				*	3 : Fail (All coil function error)
				*/
				case 1:
				case 2:
				case 3:
					cnt = 0;
					break;

				default:
					break;
				}
			}
		}
	} while (cnt--);

	wac_i2c->connection_check = (1 == buf[0]);
	printk(KERN_DEBUG
	       "[E-PEN] epen_connection : %s %d\n",
	       (1 == buf[0]) ? "Pass" : "Fail", buf[1]);

grid_check_error:
	cmd = WACOM_I2C_STOP;
	wacom_i2c_send(wac_i2c, &cmd, 1, false);

	cmd = WACOM_I2C_START;
	wacom_i2c_send(wac_i2c, &cmd, 1, false);

}
int wacom_i2c_test(struct wacom_i2c *wac_i2c)
{
	int ret, i;
	char buf, test[10];
	buf = COM_QUERY;

	ret = wacom_i2c_send(wac_i2c, &buf, sizeof(buf), false);
	if (ret > 0)
		dev_info(&wac_i2c->client->dev,
			 "%s: buf:%d, sent:%d\n",
			 __func__, buf, ret);
	else {
		dev_err(&wac_i2c->client->dev,
			 "%s: Digitizer is not active\n",
			 __func__);
		return -1;
	}

	ret = wacom_i2c_recv(wac_i2c, test, sizeof(test), false);
	if (ret >= 0) {
		for (i = 0; i < 8; i++)
		dev_info(&wac_i2c->client->dev,
			 "%s: %d\n", __func__, test[i]);
	} else {
		dev_err(&wac_i2c->client->dev,
			 "%s: Digitizer does not reply\n",
			 __func__);
		return -1;
	}

	return 0;
}
コード例 #5
0
static bool flash_blver(struct wacom_i2c *wac_i2c, int *blver)
{
	u8 command[CMD_SIZE];
	u8 response[RSP_SIZE];
	int ret, ECH;
	int len = 0;

	command[len++] = 4;	/* Command Register-LSB */
	command[len++] = 0;	/* Command Register-MSB */
	command[len++] = 0x37;	/* Command-LSB, ReportType:Feature(11) ReportID:7 */
	command[len++] = CMD_SET_FEATURE;	/* Command-MSB, SET_REPORT */
	command[len++] = 5;	/* Data Register-LSB */
	command[len++] = 0;	/* Data-Register-MSB */
	command[len++] = 5;	/* Length Field-LSB */
	command[len++] = 0;	/* Length Field-MSB */
	command[len++] = BOOT_CMD_REPORT_ID;	/* Report:ReportID */
	command[len++] = BOOT_BLVER;	/* Report:Boot Version command */
	command[len++] = ECH = 7;	/* Report:echo */

	ret = wacom_i2c_send(wac_i2c, command, len, WACOM_I2C_MODE_BOOT);
	if (ret < 0) {
		printk(KERN_DEBUG"epen:%s 2 ret:%d \n", __func__, ret);
		return false;
	}

	len = 0;
	command[len++] = 4;	/* Command Register-LSB */
	command[len++] = 0;	/* Command Register-MSB */
	command[len++] = 0x38;	/* Command-LSB, ReportType:Feature(11) ReportID:8 */
	command[len++] = CMD_GET_FEATURE;	/* Command-MSB, GET_REPORT */
	command[len++] = 5;	/* Data Register-LSB */
	command[len++] = 0;	/* Data Register-MSB */

	ret = wacom_i2c_send(wac_i2c, command, len, WACOM_I2C_MODE_BOOT);
	if (ret < 0) {
		printk(KERN_DEBUG"epen:%s 4 ret:%d \n", __func__, ret);
		return false;
	}

	msleep(10);

	ret =
	    wacom_i2c_recv(wac_i2c, response, BOOT_RSP_SIZE,
			   WACOM_I2C_MODE_BOOT);
	if (ret < 0) {
		printk(KERN_DEBUG"epen:%s 5 ret:%d \n", __func__, ret);
		return false;
	}

	if ((response[3] != BOOT_CMD) || (response[4] != ECH)) {
		printk(KERN_DEBUG"epen:%s res[3]:%x res[4]:%x \n", __func__, response[3],
		       response[4]);
		return false;
	}

	*blver = (int)response[5];

	return true;
}
コード例 #6
0
int wacom_checksum(struct wacom_i2c *wac_i2c)
{
	int ret = 0, retry = 10;
	int i = 0;
	u8 buf[5] = {0, };

	buf[0] = COM_CHECKSUM;

	while (retry--) {
		ret = wacom_i2c_send(wac_i2c, &buf[0], 1, false);
		if (ret < 0) {
			printk(KERN_DEBUG
			       "[E-PEN] i2c fail, retry, %d\n",
			       __LINE__);
			continue;
		}

		msleep(200);
		ret = wacom_i2c_recv(wac_i2c, buf, 5, false);
		if (ret < 0) {
			printk(KERN_DEBUG
			       "[E-PEN] i2c fail, retry, %d\n",
			       __LINE__);
			continue;
		} else if (buf[0] == 0x1f)
			break;
		printk(KERN_DEBUG "[E-PEN] checksum retry\n");
	}

	if (ret >= 0) {
		printk(KERN_DEBUG
		       "[E-PEN] received checksum %x, %x, %x, %x, %x\n",
		       buf[0], buf[1], buf[2], buf[3], buf[4]);
	}

	for (i = 0; i < 5; ++i) {
		if (buf[i] != Firmware_checksum[i]) {
			printk(KERN_DEBUG
			       "[E-PEN] checksum fail %dth %x %x\n", i,
			       buf[i], Firmware_checksum[i]);
			break;
		}
	}

	wac_i2c->checksum_result = (5 == i);

#ifdef WACOM_CONNECTION_CHECK
	if (!wac_i2c->connection_check)
		wacom_open_test(wac_i2c);
#endif

	return ret;
}
int wacom_checksum(struct wacom_i2c *wac_i2c)
{
	int ret = 0, retry = 10;
	int i = 0;
	u8 buf[5] = {0, };

	buf[0] = COM_CHECKSUM;

	while (retry--) {
		ret = wacom_i2c_send(wac_i2c, &buf[0], 1, false);
		if (ret < 0) {
			dev_err(&wac_i2c->client->dev,
					 "%s: i2c fail, retry, %d\n",
				      __func__, __LINE__);
			continue;
		}

		msleep(200);
		ret = wacom_i2c_recv(wac_i2c, buf, 5, false);
		if (ret < 0) {
			dev_err(&wac_i2c->client->dev,
					 "%s: i2c fail, retry, %d\n",
					 __func__, __LINE__);
			continue;
		} else if (buf[0] == 0x1f)
			break;
		dev_info(&wac_i2c->client->dev,
				 "%s: checksum retry\n",
				 __func__);
	}

	if (ret >= 0) {
		dev_info(&wac_i2c->client->dev,
				 "%s: received checksum %x, %x, %x, %x, %x\n",
				__func__, buf[0], buf[1],
				buf[2], buf[3], buf[4]);
	}

	for (i = 0; i < 5; ++i) {
		if (buf[i] != Firmware_checksum[i]) {
		dev_info(&wac_i2c->client->dev,
				 "%s: checksum fail %dth %x %x\n",
				__func__, i, buf[i],
				Firmware_checksum[i]);
			break;
		}
	}

	wac_i2c->checksum_result = (5 == i);

	return ret;
}
int wacom_checksum(struct wacom_i2c *wac_i2c)
{
	int ret = 0, retry = 10;
	int i = 0;
	u8 buf[5] = {0, };

	buf[0] = COM_CHECKSUM;

	while (retry--) {
		ret = wacom_i2c_send(wac_i2c, &buf[0], 1, false);
		if (ret < 0) {
			printk(KERN_DEBUG
			       "epen:i2c fail, retry, %d\n",
			       __LINE__);
			continue;
		}

		msleep(200);
		ret = wacom_i2c_recv(wac_i2c, buf, 5, false);
		if (ret < 0) {
			printk(KERN_DEBUG
			       "epen:i2c fail, retry, %d\n",
			       __LINE__);
			continue;
		} else if (buf[0] == 0x1f)
			break;
		printk(KERN_DEBUG "epen:checksum retry\n");
	}

	if (ret >= 0) {
		printk(KERN_DEBUG
		       "epen:received checksum %x, %x, %x, %x, %x\n",
		       buf[0], buf[1], buf[2], buf[3], buf[4]);
	}

	for (i = 0; i < 5; ++i) {
		if (buf[i] != fw_chksum[i]) {
			printk(KERN_DEBUG
			       "epen:checksum fail %dth %x %x\n", i,
			       buf[i], fw_chksum[i]);
			break;
		}
	}

	wac_i2c->checksum_result = (5 == i);

	return ret;
}
コード例 #9
0
static void wacom_i2c_resume_work(struct work_struct *work)
{
struct wacom_i2c *wac_i2c =
	    container_of(work, struct wacom_i2c, resume_work.work);
	u8 irq_state = 0;
	int ret = 0;

	irq_state = wac_i2c->wac_pdata->get_irq_state();
	wacom_enable_irq(wac_i2c, true);

	if (unlikely(irq_state)) {
		printk(KERN_DEBUG"epen:irq was enabled\n");
		ret = wacom_i2c_recv(wac_i2c, wac_i2c->wac_feature->data, COM_COORD_NUM, false);
		if (ret < 0) {
			printk(KERN_ERR "epen:%s failed to read i2c.L%d\n", __func__,
			__LINE__);
		}
	}

	printk(KERN_DEBUG "epen:%s\n", __func__);
}
コード例 #10
0
bool flash_devcieType(struct wacom_i2c *wac_i2c)
{
    int rv;
    u8 buf[4];
    u16 len;

    len = 0;
    buf[len++] = 4;
    buf[len++] = 0;
    buf[len++] = 0x32;
    buf[len++] = CMD_GET_FEATURE;

    rv = wacom_i2c_send(wac_i2c, buf, len, false);
    if (rv < 0) {
        pr_err("wacom: %s(%d) %d\n",
               __func__, rv, __LINE__);
        return false;
    }

    len = 0;
    buf[len++] = 5;
    buf[len++] = 0;

    rv = wacom_i2c_send(wac_i2c, buf, len, false);
    if (rv < 0) {
        pr_err("wacom: %s(%d) %d\n",
               __func__, rv, __LINE__);
        return false;
    }

    rv = wacom_i2c_recv(wac_i2c, buf, 4, false);
    if (rv < 0) {
        pr_err("wacom: %s(%d) %d\n",
               __func__, rv, __LINE__);
        return false;
    }

    return true;
}
コード例 #11
0
int wacom_i2c_query(struct wacom_i2c *wac_i2c)
{
	struct wacom_g5_platform_data *pdata = wac_i2c->pdata;
	struct wacom_features *wac_feature = wac_i2c->wac_feature;
	u8 data[COM_QUERY_BUFFER] = {0, };
	u8 *query = data + COM_QUERY_POS;
	int read_size = COM_QUERY_BUFFER;
	u8 buf = COM_QUERY;
	int ret;
	int i;
	int max_x, max_y, pressure;

	for (i = 0; i < COM_QUERY_RETRY; i++) {
		if (unlikely(pdata->use_query_cmd)) {
			ret = wacom_i2c_send(wac_i2c, &buf, 1, false);
			if (ret < 0) {
				printk(KERN_ERR"epen:I2C send failed(%d)\n", ret);
				msleep(50);
				continue;
			}
			read_size = COM_QUERY_NUM;
			query = data;
			msleep(50);
		}

		ret = wacom_i2c_recv(wac_i2c, data, read_size, false);
		if (ret < 0) {
			printk(KERN_ERR"epen:I2C recv failed(%d)\n", ret);
			continue;
		}

		printk(KERN_INFO "epen:%s: %dth ret of wacom query=%d\n",
		       __func__, i, ret);

		if (read_size != ret) {
			printk(KERN_ERR"epen:read size error %d of %d\n", ret, read_size);
			continue;
		}

		if (0x0f == query[EPEN_REG_HEADER]) {
			wac_feature->fw_version =
				((u16) query[EPEN_REG_FWVER1] << 8) + (u16) query[EPEN_REG_FWVER2];
			break;
		}

		printk(KERN_ERR
				"epen:%X, %X, %X, %X, %X, %X, %X, fw=0x%x\n",
				query[0], query[1], query[2], query[3],
				query[4], query[5], query[6],
				wac_feature->fw_version);
	}

	printk(KERN_NOTICE
		"epen:%X, %X, %X, %X, %X, %X, %X, %X, %X, %X, %X, %X, %X, %X\n", query[0],
		query[1], query[2], query[3], query[4], query[5], query[6],
		query[7], query[8], query[9], query[10], query[11], query[12], query[13]);

	if (i == COM_QUERY_RETRY || ret < 0) {
		printk(KERN_ERR"epen:%s:failed to read query\n", __func__);
		wac_feature->fw_version = 0;
		wac_i2c->query_status = false;
		return ret;
	}
	wac_i2c->query_status = true;

	max_x = ((u16) query[EPEN_REG_X1] << 8) + (u16) query[EPEN_REG_X2];
	max_y = ((u16) query[EPEN_REG_Y1] << 8) + (u16) query[EPEN_REG_Y2];
	pressure = ((u16) query[EPEN_REG_PRESSURE1] << 8) + (u16) query[EPEN_REG_PRESSURE2];

	printk(KERN_NOTICE"epen:q max_x=%d max_y=%d, max_pressure=%d\n",
		max_x, max_y, pressure);
	printk(KERN_NOTICE"epen:p max_x=%d max_y=%d, max_pressure=%d\n",
		pdata->max_x, pdata->max_y, pdata->max_pressure);
	printk(KERN_NOTICE "epen:fw_version=0x%X (d7:0x%X,d8:0x%X)\n",
	       wac_feature->fw_version, query[EPEN_REG_FWVER1], query[EPEN_REG_FWVER2]);
	printk(KERN_NOTICE "epen:mpu %#x, bl %#x, tx %d, ty %d, h %d\n",
		query[EPEN_REG_MPUVER], query[EPEN_REG_BLVER],
		query[EPEN_REG_TILT_X], query[EPEN_REG_TILT_Y],
		query[EPEN_REG_HEIGHT]);

	return ret;
}
コード例 #12
0
bool flash_marking(struct wacom_i2c *wac_i2c,
                   bool bMarking, int iMpuID)
{
    const int MAX_CMD_SIZE = 12 + FLASH_BLOCK_SIZE + 2;
    int rv, ECH;
    unsigned char flash_data[FLASH_BLOCK_SIZE];
    unsigned char buf[300];
    unsigned char response[RSP_SIZE];
    unsigned char sum;
    int len;
    unsigned int i, j;
    unsigned char command[MAX_CMD_SIZE];

    for (i = 0; i < FLASH_BLOCK_SIZE; i++)
        flash_data[i] = 0xFF;

    if (bMarking)
        flash_data[56] = 0x00;

    len = 0;
    buf[len++] = 4;
    buf[len++] = 0;
    buf[len++] = 0x37;
    buf[len++] = CMD_SET_FEATURE;

    rv = wacom_i2c_send(wac_i2c,
                        buf, len, false);
    if (rv < 0)
        return false;

    command[0] = 5;
    command[1] = 0;
    command[2] = 76;
    command[3] = 0;
    command[4] = BOOT_CMD_REPORT_ID;
    command[5] = BOOT_WRITE_FLASH;
    command[6] = ECH = 1;
    command[7] = 0xC0;
    command[8] = 0x1F;
    command[9] = 0x01;
    command[10] = 0x00;
    command[11] = 8;

    sum = 0;
    for (j = 0; j < 12; j++)
        sum += command[j];
    command[MAX_CMD_SIZE - 2] = ~sum + 1;

    sum = 0;
    for (i = 12; i < (FLASH_BLOCK_SIZE + 12); i++) {
        command[i] = flash_data[i-12];
        sum += flash_data[i-12];
    }

    /* Report:data checksum */
    command[MAX_CMD_SIZE - 1] = ~sum + 1;


    rv = wacom_i2c_send(wac_i2c,
                        command, BOOT_CMD_SIZE, false);
    if (rv < 0) {
        pr_err("wacom: %s(%d) %d\n",
               __func__, rv, __LINE__);
        return false;
    }

    usleep(10000);

    len = 0;
    buf[len++] = 4;
    buf[len++] = 0;
    buf[len++] = 0x38;
    buf[len++] = CMD_GET_FEATURE;

    rv = wacom_i2c_send(wac_i2c,
                        buf, len, false);
    if (rv < 0) {
        pr_err("wacom: %s(%d) %d\n",
               __func__, rv, __LINE__);
        return false;
    }

    len = 0;
    buf[len++] = 5;
    buf[len++] = 0;

    rv = wacom_i2c_send(wac_i2c,
                        buf, len, false);
    if (rv < 0) {
        pr_err("wacom: %s(%d) %d\n",
               __func__, rv, __LINE__);
        return false;
    }

    pr_info("wacom: %s confirming marking\n", __func__);
    rv = wacom_i2c_recv(wac_i2c,
                        response, BOOT_RSP_SIZE, false);
    if (rv < 0) {
        pr_err("wacom: %s(%d) %d\n",
               __func__, rv, __LINE__);
        return false;
    }

    if ((response[3] != 1) ||
            (response[4] != ECH) ||
            (response[5] != ACK)) {
        pr_err(
            "wacom: %s failing res3:%d res4:%d res5:%d\n",
            __func__, response[3], response[4], response[5]);
        return false;
    }

    return true;
}
コード例 #13
0
static ssize_t epen_connection_show(struct device *dev,
					 struct device_attribute *attr,
					 char *buff)
{
	struct wacom_i2c *wac_i2c = dev_get_drvdata(dev);
	u8 cmd = 0;
	u8 buf[2] = {0,};
	int ret = 0, cnt = 10;

	disable_irq(wac_i2c->client->irq);

	cmd = WACOM_I2C_STOP;
	ret = wacom_i2c_send(wac_i2c, &cmd, 1, false);
	if (ret <= 0) {
		dev_err(&wac_i2c->client->dev,
			 "%s: failed to send stop command\n",
			 __func__);
		goto grid_check_error;
	}

	cmd = WACOM_I2C_GRID_CHECK;
	ret = wacom_i2c_send(wac_i2c, &cmd, 1, false);
	if (ret <= 0) {
		dev_err(&wac_i2c->client->dev,
			 "%s: failed to send stop command\n",
			 __func__);
		goto grid_check_error;
	}

	cmd = WACOM_STATUS;
	do {
		msleep(50);
		if (1 == wacom_i2c_send(wac_i2c, &cmd, 1, false)) {
			if (2 == wacom_i2c_recv(wac_i2c,
						buf, 2, false)) {
				switch (buf[0]) {
				/*
				*	status value
				*	0 : data is not ready
				*	1 : PASS
				*	2 : Fail (coil function error)
				*	3 : Fail (All coil function error)
				*/
				case 1:
				case 2:
				case 3:
					cnt = 0;
					break;

				default:
					break;
				}
			}
		}
	} while (cnt--);

	dev_info(&wac_i2c->client->dev,
			 "%s : status: %x, error code: %x\n",
		       __func__, buf[0], buf[1]);

grid_check_error:
	cmd = WACOM_I2C_STOP;
	ret = wacom_i2c_send(wac_i2c, &cmd, 1, false);
	if (ret <= 0)
		dev_err(&wac_i2c->client->dev,
			 "%s: failed to send stop command\n",
			 __func__);

	cmd = WACOM_I2C_START;
	wacom_i2c_send(wac_i2c, &cmd, 1, false);
	if (ret <= 0)
		dev_err(&wac_i2c->client->dev,
			 "%s: failed to send stop command\n",
			 __func__);

	enable_irq(wac_i2c->client->irq);

	if ((buf[0] == 0x1) && (buf[1] == 0))
		return sprintf(buff, "%s\n", "OK");
	else
		return sprintf(buff, "%s\n", "NG");
}
コード例 #14
0
static bool flash_verify(struct wacom_i2c *wac_i2c,
	unsigned char *flash_data, size_t data_size,
	unsigned long start_address,
	unsigned long *max_address, int mpuType)
{
	int ECH;
	unsigned long ulAddress;
	bool rv;
	unsigned long pageNo = 0;
	u8 command_id = 0;
	printk(KERN_DEBUG "epen:verify starts\n");
	for (ulAddress = start_address; ulAddress < *max_address;
		ulAddress += FLASH_BLOCK_SIZE) {
		const int MAX_CMD_SIZE = 12 + FLASH_BLOCK_SIZE + 2;
		unsigned char buf[300];
		unsigned char sum;
		int len;
		unsigned int i, j;
		unsigned char command[MAX_CMD_SIZE];
		unsigned char response[RSP_SIZE];

		len = 0;
		buf[len++] = 4;
		buf[len++] = 0;
		buf[len++] = 0x37;
		buf[len++] = CMD_SET_FEATURE;

		rv = wacom_i2c_send(wac_i2c, buf, len, WACOM_I2C_MODE_BOOT);
		if (rv < 0) {
			printk(KERN_DEBUG "epen:1 rv:%d\n", rv);
			return false;
		}

		command[0] = 5;
		command[1] = 0;
		command[2] = 76;
		command[3] = 0;
		command[4] = BOOT_CMD_REPORT_ID;
		command[5] = BOOT_VERIFY_FLASH;
		command[6] = ECH = ++command_id;
		command[7] = ulAddress & 0x000000ff;
		command[8] = (ulAddress & 0x0000ff00) >> 8;
		command[9] = (ulAddress & 0x00ff0000) >> 16;
		command[10] = (ulAddress & 0xff000000) >> 24;
		command[11] = 8;

		sum = 0;
		for (j = 0; j < 12; j++)
			sum += command[j];
		command[MAX_CMD_SIZE - 2] = ~sum + 1;

		sum = 0;
		for (i = 12; i < (FLASH_BLOCK_SIZE + 12); i++) {
			command[i] = flash_data[ulAddress + (i - 12)];
			sum += flash_data[ulAddress + (i - 12)];
		}
		command[MAX_CMD_SIZE - 1] = ~sum + 1;

		rv = wacom_i2c_send(wac_i2c, command, BOOT_CMD_SIZE,
			WACOM_I2C_MODE_BOOT);
		if (rv < 0) {
			printk(KERN_DEBUG "epen:2 rv:%d\n", rv);
			return false;
		}

		if (ulAddress <= 0x0ffff)
			ndelay(250000);
		else if (ulAddress >= 0x10000 && ulAddress <= 0x20000)
			ndelay(350000);
		else
			usleep_range(10000, 10000);

		len = 0;
		buf[len++] = 4;
		buf[len++] = 0;
		buf[len++] = 0x38;
		buf[len++] = CMD_GET_FEATURE;

		rv = wacom_i2c_send(wac_i2c, buf, len, WACOM_I2C_MODE_BOOT);
		if (rv < 0) {
			printk(KERN_DEBUG "epen:3 rv:%d\n", rv);
			return false;
		}

		len = 0;
		buf[len++] = 5;
		buf[len++] = 0;

		rv = wacom_i2c_send(wac_i2c, buf, len, WACOM_I2C_MODE_BOOT);
		if (rv < 0) {
			printk(KERN_DEBUG "epen:4 rv:%d\n", rv);
			return false;
		}

		rv = wacom_i2c_recv(wac_i2c, response, BOOT_RSP_SIZE,
			WACOM_I2C_MODE_BOOT);
		if (rv < 0) {
			printk(KERN_DEBUG "epen:5 rv:%d\n", rv);
			return false;
		}

		if ((response[3] != VERIFY_CMD) ||
			(response[4] != ECH) || (response[5] != ACK)) {
				printk(KERN_DEBUG "epen:res3:%d res4:%d res5:%d\n",
					response[3], response[4], response[5]);
				return false;
		}
		pageNo++;
	}

	return true;
}
コード例 #15
0
static bool is_flash_marking(struct wacom_i2c *wac_i2c,
	size_t data_size, bool *bMarking, int iMpuID)
{
	const int MAX_CMD_SIZE = (12 + FLASH_BLOCK_SIZE + 2);
	int rv, ECH;
	unsigned char flash_data[FLASH_BLOCK_SIZE];
	unsigned char buf[300];
	unsigned char sum;
	int len;
	unsigned int i, j;
	unsigned char response[RSP_SIZE];
	unsigned char command[MAX_CMD_SIZE];

	*bMarking = false;

	printk(KERN_DEBUG "epen:started\n");
	for (i = 0; i < FLASH_BLOCK_SIZE; i++)
		flash_data[i] = 0xFF;

	flash_data[56] = 0x00;

	len = 0;
	buf[len++] = 4;
	buf[len++] = 0;
	buf[len++] = 0x37;
	buf[len++] = CMD_SET_FEATURE;

	rv = wacom_i2c_send(wac_i2c, buf, len, WACOM_I2C_MODE_BOOT);
	if (rv < 0) {
		printk(KERN_DEBUG "epen:1 rv:%d\n", rv);
		return false;
	}

	command[0] = 5;
	command[1] = 0;
	command[2] = 76;
	command[3] = 0;
	command[4] = BOOT_CMD_REPORT_ID;
	command[5] = BOOT_VERIFY_FLASH;
	command[6] = ECH = 1;
	command[7] = 0xC0;
	command[8] = 0x1F;
	command[9] = 0x01;
	command[10] = 0x00;
	command[11] = 8;

	sum = 0;
	for (j = 0; j < 12; j++)
		sum += command[j];

	command[MAX_CMD_SIZE - 2] = ~sum + 1;

	sum = 0;
	printk(KERN_DEBUG "epen:start writing command\n");
	for (i = 12; i < (FLASH_BLOCK_SIZE + 12); i++) {
		command[i] = flash_data[i - 12];
		sum += flash_data[i - 12];
	}
	command[MAX_CMD_SIZE - 1] = ~sum + 1;

	printk(KERN_DEBUG "epen:sending command\n");
	rv = wacom_i2c_send(wac_i2c, command, MAX_CMD_SIZE,
		WACOM_I2C_MODE_BOOT);
	if (rv < 0) {
		printk(KERN_DEBUG "epen:2 rv:%d\n", rv);
		return false;
	}

	usleep_range(10000, 10000);

	len = 0;
	buf[len++] = 4;
	buf[len++] = 0;
	buf[len++] = 0x38;
	buf[len++] = CMD_GET_FEATURE;

	rv = wacom_i2c_send(wac_i2c, buf, len, WACOM_I2C_MODE_BOOT);
	if (rv < 0) {
		printk(KERN_DEBUG "epen:3 rv:%d\n", rv);
		return false;
	}

	len = 0;
	buf[len++] = 5;
	buf[len++] = 0;

	rv = wacom_i2c_send(wac_i2c, buf, len, WACOM_I2C_MODE_BOOT);
	if (rv < 0) {
		printk(KERN_DEBUG "epen:4 rv:%d\n", rv);
		return false;
	}

	rv = wacom_i2c_recv(wac_i2c, response, RSP_SIZE, WACOM_I2C_MODE_BOOT);
	if (rv < 0) {
		printk(KERN_DEBUG "epen:5 rv:%d\n", rv);
		return false;
	}

	printk(KERN_DEBUG "epen:checking response\n");
	if ((response[3] != MARK_CMD) ||
		(response[4] != ECH) || (response[5] != ACK)) {
			printk(KERN_DEBUG "epen:fails res3:%d res4:%d res5:%d\n",
				response[3], response[4], response[5]);
			return false;
	}

	*bMarking = true;
	return true;
}
コード例 #16
0
bool flash_erase(struct wacom_i2c *wac_i2c, bool bAllUserArea,
                 int *eraseBlock, int num)
{
    int rv, ECH;
    unsigned char sum;
    unsigned char buf[72];
    unsigned char cmd_chksum;
    u16 len;
    int i, j;
    unsigned char command[CMD_SIZE];
    unsigned char response[RSP_SIZE];

    for (i = 0; i < num; i++) {
        msleep(500);
retry:
        len = 0;
        buf[len++] = 4;
        buf[len++] = 0;
        buf[len++] = 0x37;
        buf[len++] = CMD_SET_FEATURE;

        pr_info("wacom: %s sending SET_FEATURE:%d\n", __func__, i);

        rv = wacom_i2c_send(wac_i2c, buf, len, false);
        if (rv < 0) {
            pr_err("wacom: %s(%d) %d\n",
                   __func__, rv, __LINE__);
            return false;
        }

        pr_info("wacom: %s setting a command:%d\n", __func__, i);

        command[0] = 5;
        command[1] = 0;
        command[2] = 7;
        command[3] = 0;
        command[4] = BOOT_CMD_REPORT_ID;
        command[5] = BOOT_ERASE_FLASH;
        command[6] = ECH = i;
        command[7] = *eraseBlock;
        eraseBlock++;

        sum = 0;
        for (j = 0; j < 8; j++)
            sum += command[j];
        cmd_chksum = ~sum+1;
        command[8] = cmd_chksum;

        rv = wacom_i2c_send(wac_i2c, command, 9, false);
        if (rv < 0) {
            pr_err("wacom: %s(%d) %d\n",
                   __func__, rv, __LINE__);
            return false;
        }

        msleep(5000);

        len = 0;
        buf[len++] = 4;
        buf[len++] = 0;
        buf[len++] = 0x38;
        buf[len++] = CMD_GET_FEATURE;

        pr_info("wacom: %s sending GET_FEATURE :%d\n", __func__, i);
        rv = wacom_i2c_send(wac_i2c, buf, len, false);
        if (rv < 0) {
            pr_err("wacom: %s(%d) %d\n",
                   __func__, rv, __LINE__);
            return false;
        }

        len = 0;
        buf[len++] = 5;
        buf[len++] = 0;

        rv = wacom_i2c_send(wac_i2c, buf, len, false);
        if (rv < 0) {
            pr_err("wacom: %s(%d) %d\n",
                   __func__, rv, __LINE__);
            return false;
        }

        rv = wacom_i2c_recv(wac_i2c, response, BOOT_RSP_SIZE, false);
        if (rv < 0) {
            pr_err("wacom: %s(%d) %d\n",
                   __func__, rv, __LINE__);
            return false;
        }

        if ((response[3] != ERS_CMD) ||
                (response[4] != ECH)) {
            pr_err("wacom: %s failing 5:%d\n", __func__, i);
            return false;
        }

        if (response[5] == 0x80) {
            pr_err("wacom: %s retry\n", __func__);
            goto retry;
        }
        if (response[5] != ACK) {
            pr_err("wacom: %s failing 6:%d res5:%d\n", __func__,
                   i, response[5]);
            return false;
        }
        pr_info("wacom: %s %d\n", __func__, i);
    }
    return true;
}
コード例 #17
0
int wacom_i2c_query(struct wacom_i2c *wac_i2c)
{
	struct wacom_features *wac_feature = wac_i2c->wac_feature;
	int ret;
	u8 buf;
	u8 data[9] = {0, };
	int i = 0;
	int query_limit = 10;

	buf = COM_QUERY;

	for (i = 0; i < query_limit; i++) {
		ret = wacom_i2c_send(wac_i2c, &buf, 1, false);
		if (ret < 0) {
			printk(KERN_ERR"[E-PEN] I2C send failed(%d)\n", ret);
			continue;
		}
		msleep(100);
		ret = wacom_i2c_recv(wac_i2c, data, COM_QUERY_NUM, false);
		if (ret < 0) {
			printk(KERN_ERR"[E-PEN] I2C recv failed(%d)\n", ret);
			continue;
		}
		printk(KERN_INFO "[E-PEN] %s: %dth ret of wacom query=%d\n",
		       __func__, i, ret);
		if (COM_QUERY_NUM == ret) {
			if (0x0f == data[0]) {
				wac_feature->fw_version =
					((u16) data[7] << 8) + (u16) data[8];
				break;
			} else {
				printk(KERN_NOTICE
				       "[E-PEN] %X, %X, %X, %X, %X, %X, %X, fw=0x%x\n",
				       data[0], data[1], data[2], data[3],
				       data[4], data[5], data[6],
				       wac_feature->fw_version);
			}
		}
	}

#if defined(CONFIG_MACH_Q1_BD)\
	|| defined(CONFIG_MACH_P4NOTE)\
	|| defined(CONFIG_MACH_T0)
	wac_feature->x_max = (u16) WACOM_MAX_COORD_X;
	wac_feature->y_max = (u16) WACOM_MAX_COORD_Y;
#else
	wac_feature->x_max = ((u16) data[1] << 8) + (u16) data[2];
	wac_feature->y_max = ((u16) data[3] << 8) + (u16) data[4];
#endif
	wac_feature->pressure_max = (u16) data[6] + ((u16) data[5] << 8);

#if defined(COOR_WORK_AROUND)
	if (i == 10 || ret < 0) {
		printk(KERN_NOTICE "[E-PEN] COOR_WORK_AROUND is applied\n");
		printk(KERN_NOTICE
		       "[E-PEN] %X, %X, %X, %X, %X, %X, %X, %X, %X\n", data[0],
		       data[1], data[2], data[3], data[4], data[5], data[6],
		       data[7], data[8]);
		wac_feature->x_max = (u16) WACOM_MAX_COORD_X;
		wac_feature->y_max = (u16) WACOM_MAX_COORD_Y;
		wac_feature->pressure_max = (u16) WACOM_MAX_PRESSURE;
#ifdef CONFIG_MACH_T0
		wac_feature->fw_version = 0;
#else
		wac_feature->fw_version = 0xFF;
#endif
	}
#endif

	printk(KERN_NOTICE "[E-PEN] x_max=0x%X\n", wac_feature->x_max);
	printk(KERN_NOTICE "[E-PEN] y_max=0x%X\n", wac_feature->y_max);
	printk(KERN_NOTICE "[E-PEN] pressure_max=0x%X\n",
	       wac_feature->pressure_max);
	printk(KERN_NOTICE "[E-PEN] fw_version=0x%X (d7:0x%X,d8:0x%X)\n",
	       wac_feature->fw_version, data[7], data[8]);
	printk(KERN_NOTICE "[E-PEN] %X, %X, %X, %X, %X, %X, %X, %X, %X\n",
	       data[0], data[1], data[2], data[3], data[4], data[5], data[6],
	       data[7], data[8]);

	if ((i == 10) && (ret < 0)) {
		printk(KERN_DEBUG"[E-PEN] %s, failed\n", __func__);
		wac_i2c->query_status = false;
		return ret;
	}
	wac_i2c->query_status = true;

#if defined(CONFIG_MACH_P4NOTE)
	wacom_checksum(wac_i2c);
#endif

	return 0;
}
コード例 #18
0
static bool flash_erase(struct wacom_i2c *wac_i2c,
			int *eraseBlock, int num)
{
	int rv, ECH;
	unsigned char sum;
	unsigned char buf[72];
	unsigned char cmd_chksum;
	u16 len;
	int i, j;
	unsigned char command[CMD_SIZE];
	unsigned char response[RSP_SIZE];

	for (i = 0; i < num; i++) {
		/*msleep(500);*/
retry:
		if (epen_debug)
			printk(KERN_DEBUG"epen:erase count %d\n", i);
		len = 0;
		buf[len++] = 4;
		buf[len++] = 0;
		buf[len++] = 0x37;
		buf[len++] = CMD_SET_FEATURE;

		rv = wacom_i2c_send(wac_i2c, buf, len, WACOM_I2C_MODE_BOOT);
		if (rv < 0) {
			printk(KERN_DEBUG "epen:failing 1:%d\n", i);
			return false;
		}

		command[0] = 5;
		command[1] = 0;
		command[2] = 7;
		command[3] = 0;
		command[4] = BOOT_CMD_REPORT_ID;
		command[5] = BOOT_ERASE_FLASH;
		command[6] = ECH = i;
		command[7] = *eraseBlock;
		eraseBlock++;

		sum = 0;
		for (j = 0; j < 8; j++)
			sum += command[j];
		cmd_chksum = ~sum + 1;
		command[8] = cmd_chksum;

		rv = wacom_i2c_send(wac_i2c, command, 9, WACOM_I2C_MODE_BOOT);
		if (rv < 0) {
			printk(KERN_DEBUG "epen:failing 2:%d\n", i);
			return false;
		}

#ifdef CONFIG_EPEN_WACOM_G9PL
		switch (i) {
		case 0:
		case 1:
			msleep(3000);
			break;
		case 2:
			msleep(5000);
			break;
		case 3:
			msleep(500);
			break;
		default:
			msleep(5000);
			break;
		}
#else
		msleep(300);
#endif

		len = 0;
		buf[len++] = 4;
		buf[len++] = 0;
		buf[len++] = 0x38;
		buf[len++] = CMD_GET_FEATURE;

		rv = wacom_i2c_send(wac_i2c, buf, len, WACOM_I2C_MODE_BOOT);
		if (rv < 0) {
			printk(KERN_DEBUG "epen:failing 3:%d\n", i);
			return false;
		}

		len = 0;
		buf[len++] = 5;
		buf[len++] = 0;

		rv = wacom_i2c_send(wac_i2c, buf, len, WACOM_I2C_MODE_BOOT);
		if (rv < 0) {
			printk(KERN_DEBUG "epen:failing 4:%d\n", i);
			return false;
		}

		rv = wacom_i2c_recv(wac_i2c, response, BOOT_RSP_SIZE,
				    WACOM_I2C_MODE_BOOT);
		if (rv < 0) {
			printk(KERN_DEBUG "epen:failing 5:%d\n", i);
			return false;
		}

		if ((response[3] != ERS_CMD) || (response[4] != ECH)) {
			printk(KERN_DEBUG "epen:failing 6:%d\n", i);
			return false;
		}

		if (response[5] == 0x80) {
			printk(KERN_DEBUG "epen:retry\n");
			goto retry;
		}
		if (response[5] != ACK) {
			printk(KERN_DEBUG "epen:failing 7:%d res5:%d\n", i,
			       response[5]);
			return false;
		}
	}
	return true;
}
コード例 #19
0
static void wacom_open_test(struct wacom_i2c *wac_i2c)
{
	u8 cmd = 0;
	u8 buf[2] = {0,};
	int ret = 0, retry = 10;

	cmd = WACOM_I2C_STOP;
	ret = wacom_i2c_send(wac_i2c, &cmd, 1, false);
	if (ret <= 0) {
		printk(KERN_ERR "epen:failed to send stop command\n");
		return ;
	}

	usleep_range(500, 500);

	cmd = WACOM_I2C_GRID_CHECK;
	ret = wacom_i2c_send(wac_i2c, &cmd, 1, false);
	if (ret <= 0) {
		printk(KERN_ERR "epen:failed to send stop command\n");
		goto grid_check_error;
	}

	msleep(150);

	cmd = WACOM_STATUS;
	do {
		printk(KERN_DEBUG"epen:read status, retry %d\n", retry);
		ret = wacom_i2c_send(wac_i2c, &cmd, 1, false);
		if (ret != 1) {
			printk(KERN_DEBUG"epen:failed to send cmd(ret:%d)\n", ret);
			continue;
		}
		usleep_range(500, 500);
		ret = wacom_i2c_recv(wac_i2c, buf, 2, false);
		if (ret != 2) {
			printk(KERN_DEBUG"epen:failed to recv data(ret:%d)\n", ret);
			continue;
		}

		/*
		*	status value
		*	0 : data is not ready
		*	1 : PASS
		*	2 : Fail (coil function error)
		*	3 : Fail (All coil function error)
		*/
		if (buf[0] == 1) {
			printk(KERN_DEBUG"epen:Pass\n");
			break;
		}

		printk(KERN_DEBUG"epen:buf[0]:%d, buf[1]:%d\n", buf[0], buf[1]);
		msleep(50);
	} while (retry--);

	wac_i2c->connection_check = (1 == buf[0]);
	printk(KERN_DEBUG
	       "epen:epen_connection : %s buf[1]:%d\n",
	       (1 == buf[0]) ? "Pass" : "Fail", buf[1]);

grid_check_error:
	cmd = WACOM_I2C_STOP;
	wacom_i2c_send(wac_i2c, &cmd, 1, false);

	cmd = WACOM_I2C_START;
	wacom_i2c_send(wac_i2c, &cmd, 1, false);
}
コード例 #20
0
bool flash_security_unlock(struct wacom_i2c *wac_i2c, int *status)
{
    int rv, ECH;
    u8 buf[4];
    u16 len;
    unsigned char command[CMD_SIZE];
    unsigned char response[RSP_SIZE];

    len = 0;
    buf[len++] = 4;
    buf[len++] = 0;
    buf[len++] = 0x37;
    buf[len++] = CMD_SET_FEATURE;

    rv = wacom_i2c_send(wac_i2c, buf, len, false);
    if (rv < 0) {
        pr_err("wacom: %s(%d) %d\n",
               __func__, rv, __LINE__);
        return false;
    }

    command[0] = 5;
    command[1] = 0;
    command[2] = 5;
    command[3] = 0;
    command[4] = BOOT_CMD_REPORT_ID;
    command[5] = BOOT_SECURITY_UNLOCK;
    command[6] = ECH = 7;

    rv = wacom_i2c_send(wac_i2c, command, 7, false);
    if (rv < 0) {
        pr_err("wacom: %s(%d) %d\n",
               __func__, rv, __LINE__);
        return false;
    }

    usleep(10000);

    len = 0;
    buf[len++] = 4;
    buf[len++] = 0;
    buf[len++] = 0x38;
    buf[len++] = CMD_GET_FEATURE;

    rv = wacom_i2c_send(wac_i2c, buf, len, false);
    if (rv < 0) {
        pr_err("wacom: %s(%d) %d\n",
               __func__, rv, __LINE__);
        return false;
    }

    len = 0;
    buf[len++] = 5;
    buf[len++] = 0;

    rv = wacom_i2c_send(wac_i2c, buf, len, false);
    if (rv < 0) {
        pr_err("wacom: %s(%d) %d\n",
               __func__, rv, __LINE__);
        return false;
    }

    rv = wacom_i2c_recv(wac_i2c, response, BOOT_RSP_SIZE, false);
    if (rv < 0) {
        pr_err("wacom: %s(%d) %d\n",
               __func__, rv, __LINE__);
        return false;
    }

    if ((response[3] != SEC_CMD) ||
            (response[4] != ECH))
        return false;

    *status = (int)response[5];

    return true;
}
コード例 #21
0
bool flash_query(struct wacom_i2c *wac_i2c)
{
    int rv, ECH;
    u8 buf[4];
    u16 len;
    unsigned char command[CMD_SIZE];
    unsigned char response[RSP_SIZE];

    len = 0;
    buf[len++] = 4;
    buf[len++] = 0;
    buf[len++] = 0x37;
    buf[len++] = CMD_SET_FEATURE;

    pr_info(
        "wacom: %s started buf[3]:%d len:%d\n",
        __func__, buf[3], len);
    rv = wacom_i2c_send(wac_i2c, buf, len, false);
    if (rv < 0) {
        pr_err("wacom: %s(%d) %d\n",
               __func__, rv, __LINE__);
        return false;
    }

    command[0] = 5;
    command[1] = 0;
    command[2] = 5;
    command[3] = 0;
    command[4] = BOOT_CMD_REPORT_ID;
    command[5] = BOOT_QUERY;
    command[6] = ECH = 7;

    rv = wacom_i2c_send(wac_i2c, command, 7, false);
    if (rv < 0) {
        pr_err("wacom: %s(%d) %d\n",
               __func__, rv, __LINE__);
        return false;
    }

    usleep(10000);

    len = 0;
    buf[len++] = 4;
    buf[len++] = 0;
    buf[len++] = 0x38;
    buf[len++] = CMD_GET_FEATURE;

    rv = wacom_i2c_send(wac_i2c, buf, len, false);
    if (rv < 0) {
        pr_err("wacom: %s(%d) %d\n",
               __func__, rv, __LINE__);
        return false;
    }

    len = 0;
    buf[len++] = 5;
    buf[len++] = 0;

    rv = wacom_i2c_send(wac_i2c, buf, len, false);
    if (rv < 0) {
        pr_err("wacom: %s(%d) %d\n",
               __func__, rv, __LINE__);
        return false;
    }

    rv = wacom_i2c_recv(wac_i2c, response,
                        BOOT_RSP_SIZE, false);
    if (rv < 0) {
        pr_err("wacom: %s(%d) %d\n",
               __func__, rv, __LINE__);
        return false;
    }

    if ((response[3] != QUERY_CMD) ||
            (response[4] != ECH)) {
        pr_err("wacom: %s res3:%d res4:%d\n", __func__,
               response[3], response[4]);
        return false;
    }
    if (response[5] != QUERY_RSP) {
        pr_err("wacom: %s res5:%d\n", __func__, response[5]);
        return false;
    }

    return true;
}
コード例 #22
0
bool flash_verify(struct wacom_i2c *wac_i2c,
                  unsigned char *flash_data, unsigned long start_address,
                  unsigned long *max_address, int mpuType)
{
    int ECH;
    unsigned long ulAddress;
    bool rv;
    unsigned long pageNo = 0;
    u8 command_id = 0;
    pr_info("wacom: %s verify starts\n", __func__);
    for (ulAddress = start_address; ulAddress <
            *max_address; ulAddress += FLASH_BLOCK_SIZE) {
        const int MAX_CMD_SIZE = 12 + FLASH_BLOCK_SIZE + 2;
        unsigned char buf[300];
        unsigned char sum;
        int len;
        unsigned int i, j;
        unsigned char command[MAX_CMD_SIZE];
        unsigned char response[RSP_SIZE];

        len = 0;
        buf[len++] = 4;
        buf[len++] = 0;
        buf[len++] = 0x37;
        buf[len++] = CMD_SET_FEATURE;

        rv = wacom_i2c_send(wac_i2c, buf, len, false);
        if (rv < 0)
            return false;

        command[0] = 5;
        command[1] = 0;
        command[2] = 76;
        command[3] = 0;
        command[4] = BOOT_CMD_REPORT_ID;
        command[5] = BOOT_VERIFY_FLASH;
        command[6] = ECH = ++command_id;
        command[7] = ulAddress&0x000000ff;
        command[8] = (ulAddress&0x0000ff00) >> 8;
        command[9] = (ulAddress&0x00ff0000) >> 16;
        command[10] = (ulAddress&0xff000000) >> 24;
        command[11] = 8;

        sum = 0;
        for (j = 0; j < 12; j++)
            sum += command[j];
        command[MAX_CMD_SIZE - 2] = ~sum+1;

        sum = 0;
        for (i = 12; i < (FLASH_BLOCK_SIZE + 12); i++) {
            command[i] = flash_data[ulAddress+(i-12)];
            sum += flash_data[ulAddress+(i-12)];
        }
        command[MAX_CMD_SIZE - 1] = ~sum+1;

        rv = wacom_i2c_send(wac_i2c, command, BOOT_CMD_SIZE, false);
        if (rv < 0)
            return false;

        usleep(10000);

        len = 0;
        buf[len++] = 4;
        buf[len++] = 0;
        buf[len++] = 0x38;
        buf[len++] = CMD_GET_FEATURE;

        rv = wacom_i2c_send(wac_i2c, buf, len, false);
        if (rv < 0)
            return false;

        len = 0;
        buf[len++] = 5;
        buf[len++] = 0;

        rv = wacom_i2c_send(wac_i2c, buf, len,
                            false);
        if (rv < 0)
            return false;

        rv = wacom_i2c_recv(wac_i2c, response,
                            BOOT_RSP_SIZE, false);
        if (rv < 0)
            return false;

        if ((response[3] != VERIFY_CMD) ||
                (response[4] != ECH) || (response[5] != ACK)) {
            pr_err(
                "wacom: %s res3:%d res4:%d res5:%d\n", __func__,
                response[3], response[4], response[5]);
            return false;
        }
        pageNo++;
    }

    return true;
}
コード例 #23
0
bool is_flash_marking(struct wacom_i2c *wac_i2c,
                      bool *bMarking, int iMpuID)
{
    const int MAX_CMD_SIZE = (12 + FLASH_BLOCK_SIZE + 2);
    int rv, ECH;
    unsigned char flash_data[FLASH_BLOCK_SIZE];
    unsigned char buf[300];
    unsigned char sum;
    int len;
    unsigned int i, j;
    unsigned char response[RSP_SIZE];
    unsigned char command[MAX_CMD_SIZE];

    *bMarking = false;

    pr_info("wacom: %s started\n", __func__);
    for (i = 0; i < FLASH_BLOCK_SIZE; i++)
        flash_data[i] = 0xFF;

    flash_data[56] = 0x00;

    len = 0;
    buf[len++] = 4;
    buf[len++] = 0;
    buf[len++] = 0x37;
    buf[len++] = CMD_SET_FEATURE;

    rv = wacom_i2c_send(wac_i2c, buf, len, false);
    if (rv < 0) {
        pr_err("wacom: %s(%d) %d\n",
               __func__, rv, __LINE__);
        return false;
    }

    command[0] = 5;
    command[1] = 0;
    command[2] = 76;
    command[3] = 0;
    command[4] = BOOT_CMD_REPORT_ID;
    command[5] = BOOT_VERIFY_FLASH;
    command[6] = ECH = 1;
    command[7] = 0xC0;
    command[8] = 0x1F;
    command[9] = 0x01;
    command[10] = 0x00;
    command[11] = 8;

    sum = 0;
    for (j = 0; j < 12; j++)
        sum += command[j];

    command[MAX_CMD_SIZE - 2] = ~sum+1;

    sum = 0;
    pr_info("wacom: %s start writing command\n", __func__);
    for (i = 12; i < (FLASH_BLOCK_SIZE + 12); i++) {
        command[i] = flash_data[i - 12];
        sum += flash_data[i - 12];
    }
    command[MAX_CMD_SIZE - 1] = ~sum + 1;

    pr_info("wacom: %s sending command\n", __func__);
    rv = wacom_i2c_send(wac_i2c, command, MAX_CMD_SIZE, false);
    if (rv < 0) {
        pr_err("wacom: %s(%d) %d\n",
               __func__, rv, __LINE__);
        return false;
    }


    usleep(10000);

    len = 0;
    buf[len++] = 4;
    buf[len++] = 0;
    buf[len++] = 0x38;
    buf[len++] = CMD_GET_FEATURE;

    pr_info("wacom: %s sending GET_FEATURE 1\n", __func__);
    rv = wacom_i2c_send(wac_i2c, buf, len, false);
    if (rv < 0) {
        pr_err("wacom: %s(%d) %d\n",
               __func__, rv, __LINE__);
        return false;
    }


    len = 0;
    buf[len++] = 5;
    buf[len++] = 0;

    pr_info("wacom: %s sending GET_FEATURE 2\n", __func__);
    rv = wacom_i2c_send(wac_i2c, buf, len, false);
    if (rv < 0) {
        pr_err("wacom: %s(%d) %d\n",
               __func__, rv, __LINE__);
        return false;
    }


    pr_info("wacom: %s receiving GET_FEATURE\n", __func__);
    rv = wacom_i2c_recv(wac_i2c, response, RSP_SIZE, false);
    if (rv < 0) {
        pr_err("wacom: %s(%d) %d\n",
               __func__, rv, __LINE__);
        return false;
    }


    pr_info("wacom: %s checking response\n", __func__);
    if ((response[3] != MARK_CMD) ||
            (response[4] != ECH) ||
            (response[5] != ACK)) {
        pr_err("wacom: %s fails res3:%d res4:%d res5:%d\n", __func__,
               response[3], response[4], response[5]);
        return false;
    }

    *bMarking = true;
    return true;
}
コード例 #24
0
static bool flash_write(struct wacom_i2c *wac_i2c,
			unsigned char *flash_data,
			unsigned long start_address, unsigned long *max_address)
{
	bool bRet = false;
	u8 command_id = 0;
	u8 command[BOOT_RSP_SIZE];
	u8 response[BOOT_RSP_SIZE];
	int ret, i, j, len, ECH = 0, ECH_len = 0;
	int ECH_ARRAY[3];
	unsigned long ulAddress;

	j = 0;
	for (ulAddress = start_address; ulAddress < *max_address;
	     ulAddress += FLASH_BLOCK_SIZE) {
		for (i = 0; i < FLASH_BLOCK_SIZE; i++) {
			if (flash_data[ulAddress + i] != 0xFF)
				break;
		}
		if (i == (FLASH_BLOCK_SIZE))
			continue;
		/* for debug */
		//printk(KERN_DEBUG"epen:write data %#x\n", (unsigned int)ulAddress);
		bRet =
		    flash_write_block(wac_i2c, flash_data, ulAddress,
				      &command_id, &ECH);
		if (!bRet)
			return false;

		if (ECH_len == 3)
			ECH_len = 0;

		ECH_ARRAY[ECH_len++] = ECH;

		if (ECH_len == 3) {
			for (j = 0; j < 3; j++) {
				do {
					len = 0;
					command[len++] = 4;
					command[len++] = 0;
					command[len++] = 0x38;
					command[len++] = CMD_GET_FEATURE;
					command[len++] = 5;
					command[len++] = 0;

					ret =
					    wacom_i2c_send(wac_i2c,
							   command, len,
							   WACOM_I2C_MODE_BOOT);
					if (ret < 0) {
						printk(KERN_DEBUG"epen:%s failing 2:%d \n",
						       __func__, i);
						return false;
					}

					ret =
					    wacom_i2c_recv(wac_i2c,
							   response,
							   BOOT_RSP_SIZE,
							   WACOM_I2C_MODE_BOOT);
					if (ret < 0) {
						printk(KERN_DEBUG"epen:%s failing 3:%d \n",
						       __func__, i);
						return false;
					}

					if ((response[3] != 0x01
					     || response[4] != ECH_ARRAY[j])
					    || (response[5] != 0xff
						&& response[5] != 0x00))
						return false;
					//printk(KERN_DEBUG"epen:addr: %x res:%x \n", ulAddress, response[5]);
				} while (response[3] == 0x01
					 && response[4] == ECH_ARRAY[j]
					 && response[5] == 0xff);
			}
		}
	}

	return true;
}
コード例 #25
0
static bool erase_codemem(struct wacom_i2c *wac_i2c, int *eraseBlock, int num)
{
	u8 command[CMD_SIZE];
	u8 response[BOOT_RSP_SIZE];
	unsigned char sum = 0;
	unsigned char cmd_chksum;
	int ret, ECH;
	int len = 0;
	int i, j;

	for (i = 0; i < num; i++) {
		len = 0;

		command[len++] = 4;	/* Command Register-LSB */
		command[len++] = 0;	/* Command Register-MSB */
		command[len++] = 0x37;	/* Command-LSB, ReportType:Feature(11) ReportID:7 */
		command[len++] = CMD_SET_FEATURE;	/* Command-MSB, SET_REPORT */
		command[len++] = 5;	/* Data Register-LSB */
		command[len++] = 0;	/* Data-Register-MSB */
		command[len++] = 7;	/* Length Field-LSB */
		command[len++] = 0;	/* Length Field-MSB */
		command[len++] = BOOT_CMD_REPORT_ID;	/* Report:ReportID */
		command[len++] = BOOT_ERASE_FLASH;	/* Report:erase command */
		command[len++] = ECH = i;	/* Report:echo */
		command[len++] = *eraseBlock;	/* Report:erased block No. */
		eraseBlock++;

		sum = 0;
		for (j = 4; j < 12; j++)
			sum += command[j];
		cmd_chksum = ~sum + 1;	/* Report:check sum */
		command[len++] = cmd_chksum;

		ret =
		    wacom_i2c_send(wac_i2c, command, len, WACOM_I2C_MODE_BOOT);
		if (ret < 0) {
			printk(KERN_DEBUG"epen:%s failing 1:%d \n", __func__, i);
			return false;
		}

		do {
			len = 0;
			command[len++] = 4;
			command[len++] = 0;
			command[len++] = 0x38;
			command[len++] = CMD_GET_FEATURE;
			command[len++] = 5;
			command[len++] = 0;

			ret =
			    wacom_i2c_send(wac_i2c, command, len,
					   WACOM_I2C_MODE_BOOT);
			if (ret < 0) {
				printk(KERN_DEBUG"epen:%s failing 2:%d \n", __func__, i);
				return false;
			}

			ret =
			    wacom_i2c_recv(wac_i2c, response,
					   BOOT_RSP_SIZE, WACOM_I2C_MODE_BOOT);
			if (ret < 0) {
				printk(KERN_DEBUG"epen:%s failing 3:%d \n", __func__, i);
				return false;
			}

			if ((response[3] != 0x00 || response[4] != ECH)
			    || (response[5] != 0xff && response[5] != 0x00))
				return false;

		} while (response[3] == 0x00 && response[4] == ECH
			 && response[5] == 0xff);
	}

	return true;
}
コード例 #26
0
static bool flash_write_block(struct wacom_i2c *wac_i2c, char *flash_data,
			      unsigned long ulAddress, u8 *pcommand_id)
{
	const int MAX_COM_SIZE = (12 + FLASH_BLOCK_SIZE + 2);
	int len, ECH;
	unsigned char buf[300];
	int rv;
	unsigned char sum;
	unsigned char command[MAX_COM_SIZE];
	unsigned char response[RSP_SIZE];
	unsigned int i;

	len = 0;
	buf[len++] = 4;
	buf[len++] = 0;
	buf[len++] = 0x37;
	buf[len++] = CMD_SET_FEATURE;

	rv = wacom_i2c_send(wac_i2c, buf, len, WACOM_I2C_MODE_BOOT);
	if (rv < 0)
		return false;

	command[0] = 5;
	command[1] = 0;
	command[2] = 76;
	command[3] = 0;
	command[4] = BOOT_CMD_REPORT_ID;
	command[5] = BOOT_WRITE_FLASH;
	command[6] = ECH = ++(*pcommand_id);
	command[7] = ulAddress & 0x000000ff;
	command[8] = (ulAddress & 0x0000ff00) >> 8;
	command[9] = (ulAddress & 0x00ff0000) >> 16;
	command[10] = (ulAddress & 0xff000000) >> 24;
	command[11] = 8;
	sum = 0;
	for (i = 0; i < 12; i++)
		sum += command[i];
	command[MAX_COM_SIZE - 2] = ~sum + 1;

	sum = 0;
	for (i = 12; i < (FLASH_BLOCK_SIZE + 12); i++) {
		command[i] = flash_data[ulAddress + (i - 12)];
		sum += flash_data[ulAddress + (i - 12)];
	}
	command[MAX_COM_SIZE - 1] = ~sum + 1;

	rv = wacom_i2c_send(wac_i2c, command, BOOT_CMD_SIZE,
			    WACOM_I2C_MODE_BOOT);
	if (rv < 0) {
		printk(KERN_DEBUG "epen:1 rv:%d\n", rv);
		return false;
	}

	usleep_range(10000, 10000);

	len = 0;
	buf[len++] = 4;
	buf[len++] = 0;
	buf[len++] = 0x38;
	buf[len++] = CMD_GET_FEATURE;

	rv = wacom_i2c_send(wac_i2c, buf, len, WACOM_I2C_MODE_BOOT);
	if (rv < 0) {
		printk(KERN_DEBUG "epen:2 rv:%d\n", rv);
		return false;
	}

	len = 0;
	buf[len++] = 5;
	buf[len++] = 0;

	rv = wacom_i2c_send(wac_i2c, buf, len, WACOM_I2C_MODE_BOOT);
	if (rv < 0) {
		printk(KERN_DEBUG "epen:3 rv:%d\n", rv);
		return false;
	}

	rv = wacom_i2c_recv(wac_i2c, response, BOOT_RSP_SIZE,
			    WACOM_I2C_MODE_BOOT);
	if (rv < 0) {
		printk(KERN_DEBUG "epen:4 rv:%d\n", rv);
		return false;
	}

	if ((response[3] != WRITE_CMD) ||
	    (response[4] != ECH) || response[5] != ACK)
		return false;

	return true;
}
コード例 #27
0
static bool flash_query(struct wacom_i2c *wac_i2c)
{
	int rv, ECH;
	u8 buf[4];
	u16 len;
	unsigned char command[CMD_SIZE];
	unsigned char response[RSP_SIZE];

	len = 0;
	buf[len++] = 4;
	buf[len++] = 0;
	buf[len++] = 0x37;
	buf[len++] = CMD_SET_FEATURE;

	printk(KERN_DEBUG "epen:%s\n", __func__);
	rv = wacom_i2c_send(wac_i2c, buf, len, WACOM_I2C_MODE_BOOT);
	if (rv < 0) {
		printk(KERN_DEBUG "epen:1 rv:%d\n", rv);
		return false;
	}

	command[0] = 5;
	command[1] = 0;
	command[2] = 5;
	command[3] = 0;
	command[4] = BOOT_CMD_REPORT_ID;
	command[5] = BOOT_QUERY;
	command[6] = ECH = 7;

	rv = wacom_i2c_send(wac_i2c, command, 7, WACOM_I2C_MODE_BOOT);
	if (rv < 0) {
		printk(KERN_DEBUG "epen:2 rv:%d\n", rv);
		return false;
	}

	len = 0;
	buf[len++] = 4;
	buf[len++] = 0;
	buf[len++] = 0x38;
	buf[len++] = CMD_GET_FEATURE;

	rv = wacom_i2c_send(wac_i2c, buf, len, WACOM_I2C_MODE_BOOT);
	if (rv < 0) {
		printk(KERN_DEBUG "epen:3 rv:%d\n", rv);
		return false;
	}

	len = 0;
	buf[len++] = 5;
	buf[len++] = 0;

	rv = wacom_i2c_send(wac_i2c, buf, len, WACOM_I2C_MODE_BOOT);
	if (rv < 0) {
		printk(KERN_DEBUG "epen:4 rv:%d\n", rv);
		return false;
	}

#ifdef CONFIG_EPEN_WACOM_G9PL
	usleep_range(10000, 10000);
#endif

	rv = wacom_i2c_recv(wac_i2c, response, BOOT_RSP_SIZE,
			    WACOM_I2C_MODE_BOOT);
	if (rv < 0) {
		printk(KERN_DEBUG "epen:5 rv:%d\n", rv);
		return false;
	}

	if ((response[3] != QUERY_CMD) || (response[4] != ECH)) {
		printk(KERN_DEBUG "epen:res3:%d res4:%d\n", response[3],
		       response[4]);
		return false;
	}
	if (response[5] != QUERY_RSP) {
		printk(KERN_DEBUG "epen:res5:%d\n", response[5]);
		return false;
	}

	return true;
}
コード例 #28
0
static bool flash_security_unlock(struct wacom_i2c *wac_i2c, int *status)
{
	int rv, ECH;
	u8 buf[4];
	u16 len;
	unsigned char command[CMD_SIZE];
	unsigned char response[RSP_SIZE];

	len = 0;
	buf[len++] = 4;
	buf[len++] = 0;
	buf[len++] = 0x37;
	buf[len++] = CMD_SET_FEATURE;

	rv = wacom_i2c_send(wac_i2c, buf, len, WACOM_I2C_MODE_BOOT);
	if (rv < 0) {
		printk(KERN_DEBUG "epen:1 rv:%d\n", rv);
		return false;
	}

	command[0] = 5;
	command[1] = 0;
	command[2] = 5;
	command[3] = 0;
	command[4] = BOOT_CMD_REPORT_ID;
	command[5] = BOOT_SECURITY_UNLOCK;
	command[6] = ECH = 7;

	rv = wacom_i2c_send(wac_i2c, command, 7, WACOM_I2C_MODE_BOOT);
	if (rv < 0) {
		printk(KERN_DEBUG "epen:2 rv:%d\n", rv);
		return false;
	}

	usleep_range(10000, 10000);

	len = 0;
	buf[len++] = 4;
	buf[len++] = 0;
	buf[len++] = 0x38;
	buf[len++] = CMD_GET_FEATURE;

	rv = wacom_i2c_send(wac_i2c, buf, len, WACOM_I2C_MODE_BOOT);
	if (rv < 0) {
		printk(KERN_DEBUG "epen:3 rv:%d\n", rv);
		return 0;
	}

	len = 0;
	buf[len++] = 5;
	buf[len++] = 0;

	rv = wacom_i2c_send(wac_i2c, buf, len, WACOM_I2C_MODE_BOOT);
	if (rv < 0) {
		printk(KERN_DEBUG "epen:4 rv:%d\n", rv);
		return false;
	}

	usleep_range(1000, 1000);

	rv = wacom_i2c_recv(wac_i2c, response, BOOT_RSP_SIZE,
		WACOM_I2C_MODE_BOOT);
	if (rv < 0) {
		printk(KERN_DEBUG "epen:5 rv:%d\n", rv);
		return false;
	}

	if ((response[3] != SEC_CMD) || (response[4] != ECH))
		return false;

	*status = (int)response[5];

	return true;
}
int wacom_i2c_query(struct wacom_i2c *wac_i2c)
{
	struct wacom_features *wac_feature = wac_i2c->wac_feature;
	int ret;
	u8 buf;
	u8 data[COM_QUERY_NUM] = {0, };
	int i = 0;
	const int query_limit = 3;

	buf = COM_QUERY;

	dev_info(&wac_i2c->client->dev,
			"%s: start\n", __func__);
	for (i = 0; i < query_limit; i++) {
		ret = wacom_i2c_send(wac_i2c, &buf, 1, false);
		if (ret < 0) {
			dev_err(&wac_i2c->client->dev,
				 "%s: I2C send failed(%d)\n",
				 __func__, ret);
			continue;
		}
		msleep(100);
		ret = wacom_i2c_recv(wac_i2c, data, COM_QUERY_NUM, false);
		if (ret < 0) {
			dev_err(&wac_i2c->client->dev,
				"%s: I2C recv failed(%d)\n",
				__func__, ret);
			continue;
		}
		dev_info(&wac_i2c->client->dev,
				"%s: %dth ret of wacom query=%d\n",
				__func__, i, ret);
		if (COM_QUERY_NUM != ret) {
			dev_info(&wac_i2c->client->dev,
			"%s: epen:failed to read i2c(%d)\n",
			__func__, ret);
			continue;
		}
			if (0x0f == data[0]) {
				wac_feature->fw_ic_version =
					((u16) data[7] << 8) + (u16) data[8];
				break;
			} else {
				dev_info(&wac_i2c->client->dev,
				       "%s: %X, %X, %X, %X, %X, %X, %X, fw=0x%x\n",
				       __func__,
				       data[0], data[1], data[2], data[3],
				       data[4], data[5], data[6],
				       wac_feature->fw_ic_version);
			}
		}
	wac_feature->x_max = wac_i2c->wac_pdata->max_x;
	wac_feature->y_max = wac_i2c->wac_pdata->max_y;

	wac_feature->pressure_max = (u16) data[6] + ((u16) data[5] << 8);

#if defined(COOR_WORK_AROUND)
	if (i == 10 || ret < 0) {
		dev_info(&wac_i2c->client->dev,
				"%s: COOR_WORK_AROUND is applied\n",
				__func__);
		dev_info(&wac_i2c->client->dev,
		       "%s: %X, %X, %X, %X, %X, %X, %X, %X, %X\n",
		       __func__, data[0], data[1], data[2],
		       data[3], data[4], data[5], data[6],
		       data[7], data[8]);
		wac_feature->x_max = (u16) wac_i2c->wac_pdata->max_x;
		wac_feature->y_max = (u16) wac_i2c->wac_pdata->max_y;
		wac_feature->pressure_max = (u16) wac_i2c->wac_pdata->max_pressure;
		wac_feature->fw_ic_version = 0;
	}
#endif

	dev_info(&wac_i2c->client->dev,
			"%s: x_max=0x%X, y_max=0x%X\n, pressure_max=0x%X",
			__func__, wac_feature->x_max,
			wac_feature->y_max,
			wac_feature->pressure_max);
	dev_info(&wac_i2c->client->dev,
			"%s: fw_version=0x%X (d7:0x%X,d8:0x%X)\n",
			__func__, wac_feature->fw_version,
			data[7], data[8]);
	dev_info(&wac_i2c->client->dev,
			"%s: %X, %X, %X, %X, %X, %X, %X, %X, %X\n",
			__func__, data[0], data[1], data[2],
			data[3], data[4], data[5], data[6],
			data[7], data[8]);

	if ((i == query_limit) && (ret < 0)) {
		dev_info(&wac_i2c->client->dev,
				"%s: failed\n", __func__);
		wac_i2c->query_status = false;
		return ret;
	}
	wac_i2c->query_status = true;

	return wac_feature->fw_ic_version;
}
コード例 #30
0
static bool flash_blver(struct wacom_i2c *wac_i2c, int *blver)
{
	int rv, ECH;
	u8 buf[4];
	u16 len;
	unsigned char command[CMD_SIZE];
	unsigned char response[RSP_SIZE];

	len = 0;
	buf[len++] = 4;
	buf[len++] = 0;
	buf[len++] = 0x37;
	buf[len++] = CMD_SET_FEATURE;

	rv = wacom_i2c_send(wac_i2c, buf, len, WACOM_I2C_MODE_BOOT);
	if (rv < 0) {
		printk(KERN_DEBUG "epen:1 rv:%d\n", rv);
		return false;
	}

	command[0] = 5;
	command[1] = 0;
	command[2] = 5;
	command[3] = 0;
	command[4] = BOOT_CMD_REPORT_ID;
	command[5] = BOOT_BLVER;
	command[6] = ECH = 7;

	rv = wacom_i2c_send(wac_i2c, command, 7, WACOM_I2C_MODE_BOOT);
	if (rv < 0) {
		printk(KERN_DEBUG "epen:2 rv:%d\n", rv);
		return false;
	}

	usleep_range(10000, 10000);

	len = 0;
	buf[len++] = 4;
	buf[len++] = 0;
	buf[len++] = 0x38;
	buf[len++] = CMD_GET_FEATURE;

	rv = wacom_i2c_send(wac_i2c, buf, len, WACOM_I2C_MODE_BOOT);
	if (rv < 0) {
		printk(KERN_DEBUG "epen:3 rv:%d\n", rv);
		return false;
	}

	len = 0;
	buf[len++] = 5;
	buf[len++] = 0;

	rv = wacom_i2c_send(wac_i2c, buf, len, WACOM_I2C_MODE_BOOT);
	if (rv < 0) {
		printk(KERN_DEBUG "epen:4 rv:%d\n", rv);
		return false;
	}

#ifdef CONFIG_EPEN_WACOM_G9PL
	usleep_range(10000, 10000);
#else
	usleep_range(1000, 1000);
#endif

	rv = wacom_i2c_recv(wac_i2c, response, BOOT_RSP_SIZE,
			    WACOM_I2C_MODE_BOOT);
	if (rv < 0) {
		printk(KERN_DEBUG "epen:5 rv:%d\n", rv);
		return false;
	}

	if ((response[3] != BOOT_CMD) || (response[4] != ECH))
		return false;

	*blver = (int)response[5];

	return true;
}