+static int vsense_input_register(struct vsense_drvdata *ddata, int mode)
+{
+ struct input_dev *input;
+ int ret;
+
+ input = input_allocate_device();
+ if (input == NULL)
+ return -ENOMEM;
+
+ if (mode != VSENSE_MODE_ABS) {
+ /* pretend to be a mouse */
+ input_set_capability(input, EV_REL, REL_X);
+ input_set_capability(input, EV_REL, REL_Y);
+ input_set_capability(input, EV_REL, REL_WHEEL);
+ input_set_capability(input, EV_REL, REL_HWHEEL);
+ /* add fake buttons to fool X that this is a mouse */
+ input_set_capability(input, EV_KEY, BTN_LEFT);
+ input_set_capability(input, EV_KEY, BTN_RIGHT);
+ } else {
+ input->evbit[BIT_WORD(EV_ABS)] = BIT_MASK(EV_ABS);
+ input_set_abs_params(input, ABS_X, -256, 256, 0, 0);
+ input_set_abs_params(input, ABS_Y, -256, 256, 0, 0);
+ }
+
+ input->name = ddata->dev_name;
+ input->dev.parent = &ddata->client->dev;
+
+ input->id.bustype = BUS_I2C;
+ input->id.version = 0x0091;
+
+ input->open = vsense_open;
+ input->close = vsense_close;
+
+ ddata->input = input;
+ input_set_drvdata(input, ddata);
+
+ ret = input_register_device(input);
+ if (ret) {
+ dev_err(&ddata->client->dev, "failed to register input device,"
+ " error %d\n", ret);
+ input_free_device(input);
+ return ret;
+ }
+
+ ddata->mode = mode;
+ return 0;
+}
+
+static void vsense_input_unregister(struct vsense_drvdata *ddata)
+{
+ cancel_delayed_work_sync(&ddata->work);
+ input_unregister_device(ddata->input);
+}
+
+static int vsense_proc_read(char *page, char **start, off_t off, int count,
+ int *eof, void *data)
+{
+ struct vsense_drvdata *ddata = data;
+ char *p = page;
+ int len;
+
+ switch (ddata->mode) {
+ case VSENSE_MODE_MOUSE:
+ len = sprintf(p, "mouse\n");
+ break;
+ case VSENSE_MODE_SCROLL:
+ len = sprintf(p, "scroll\n");
+ break;
+ default:
+ len = sprintf(p, "absolute\n");
+ break;
+ }
+
+ *eof = 1;
+ return len + 1;
+}
+
+static int vsense_proc_write(struct file *file, const char __user *buffer,
+ unsigned long count, void *data)
+{
+ struct vsense_drvdata *ddata = data;
+ int mode = ddata->mode;
+ char buff[32], *p;
+ int ret;
+
+ count = strncpy_from_user(buff, buffer,
+ count < sizeof(buff) ? count : sizeof(buff) - 1);
+ buff[count] = 0;
+
+ p = buff + strlen(buff) - 1;
+ while (p > buff && isspace(*p))
+ p--;
+ p[1] = 0;
+
+ if (strcasecmp(buff, "mouse") == 0)
+ mode = VSENSE_MODE_MOUSE;
+ else if (strcasecmp(buff, "scroll") == 0)
+ mode = VSENSE_MODE_SCROLL;
+ else if (strcasecmp(buff, "absolute") == 0)
+ mode = VSENSE_MODE_ABS;
+ else
+ dev_err(&ddata->client->dev, "unknown mode: %s\n", buff);
+
+ if (mode != ddata->mode) {
+ disable_irq(ddata->client->irq);
+ vsense_input_unregister(ddata);
+ ret = vsense_input_register(ddata, mode);
+ if (ret)
+ dev_err(&ddata->client->dev, "failed to re-register "
+ "input as %d, code %d\n", mode, ret);
+ else
+ enable_irq(ddata->client->irq);
+ }
+
+ return count;
+}
+