📄 aiptek.c
字号:
struct aiptek *aiptek = dev_get_drvdata(dev); aiptek->newSetting.wheel = (int)simple_strtol(buf, NULL, 10); return count;}static DEVICE_ATTR(wheel, S_IRUGO | S_IWUGO, show_tabletWheel, store_tabletWheel);/*********************************************************************** * support routines for the 'execute' file. Note that this file * both displays current setting and allows for setting changing. */static ssize_t show_tabletExecute(struct device *dev, struct device_attribute *attr, char *buf){ /* There is nothing useful to display, so a one-line manual * is in order... */ return snprintf(buf, PAGE_SIZE, "Write anything to this file to program your tablet.\n");}static ssize_tstore_tabletExecute(struct device *dev, struct device_attribute *attr, const char *buf, size_t count){ struct aiptek *aiptek = dev_get_drvdata(dev); /* We do not care what you write to this file. Merely the action * of writing to this file triggers a tablet reprogramming. */ memcpy(&aiptek->curSetting, &aiptek->newSetting, sizeof(struct aiptek_settings)); if (aiptek_program_tablet(aiptek) < 0) return -EIO; return count;}static DEVICE_ATTR(execute, S_IRUGO | S_IWUGO, show_tabletExecute, store_tabletExecute);/*********************************************************************** * support routines for the 'odm_code' file. Note that this file * only displays current setting. */static ssize_t show_tabletODMCode(struct device *dev, struct device_attribute *attr, char *buf){ struct aiptek *aiptek = dev_get_drvdata(dev); return snprintf(buf, PAGE_SIZE, "0x%04x\n", aiptek->features.odmCode);}static DEVICE_ATTR(odm_code, S_IRUGO, show_tabletODMCode, NULL);/*********************************************************************** * support routines for the 'model_code' file. Note that this file * only displays current setting. */static ssize_t show_tabletModelCode(struct device *dev, struct device_attribute *attr, char *buf){ struct aiptek *aiptek = dev_get_drvdata(dev); return snprintf(buf, PAGE_SIZE, "0x%04x\n", aiptek->features.modelCode);}static DEVICE_ATTR(model_code, S_IRUGO, show_tabletModelCode, NULL);/*********************************************************************** * support routines for the 'firmware_code' file. Note that this file * only displays current setting. */static ssize_t show_firmwareCode(struct device *dev, struct device_attribute *attr, char *buf){ struct aiptek *aiptek = dev_get_drvdata(dev); return snprintf(buf, PAGE_SIZE, "%04x\n", aiptek->features.firmwareCode);}static DEVICE_ATTR(firmware_code, S_IRUGO, show_firmwareCode, NULL);static struct attribute *aiptek_attributes[] = { &dev_attr_size.attr, &dev_attr_pointer_mode.attr, &dev_attr_coordinate_mode.attr, &dev_attr_tool_mode.attr, &dev_attr_xtilt.attr, &dev_attr_ytilt.attr, &dev_attr_jitter.attr, &dev_attr_delay.attr, &dev_attr_event_count.attr, &dev_attr_diagnostic.attr, &dev_attr_odm_code.attr, &dev_attr_model_code.attr, &dev_attr_firmware_code.attr, &dev_attr_stylus_lower.attr, &dev_attr_stylus_upper.attr, &dev_attr_mouse_left.attr, &dev_attr_mouse_middle.attr, &dev_attr_mouse_right.attr, &dev_attr_wheel.attr, &dev_attr_execute.attr, NULL};static struct attribute_group aiptek_attribute_group = { .attrs = aiptek_attributes,};/*********************************************************************** * This routine is called when a tablet has been identified. It basically * sets up the tablet and the driver's internal structures. */static intaiptek_probe(struct usb_interface *intf, const struct usb_device_id *id){ struct usb_device *usbdev = interface_to_usbdev(intf); struct usb_endpoint_descriptor *endpoint; struct aiptek *aiptek; struct input_dev *inputdev; int i; int speeds[] = { 0, AIPTEK_PROGRAMMABLE_DELAY_50, AIPTEK_PROGRAMMABLE_DELAY_400, AIPTEK_PROGRAMMABLE_DELAY_25, AIPTEK_PROGRAMMABLE_DELAY_100, AIPTEK_PROGRAMMABLE_DELAY_200, AIPTEK_PROGRAMMABLE_DELAY_300 }; int err = -ENOMEM; /* programmableDelay is where the command-line specified * delay is kept. We make it the first element of speeds[], * so therefore, your override speed is tried first, then the * remainder. Note that the default value of 400ms will be tried * if you do not specify any command line parameter. */ speeds[0] = programmableDelay; aiptek = kzalloc(sizeof(struct aiptek), GFP_KERNEL); inputdev = input_allocate_device(); if (!aiptek || !inputdev) { warn("aiptek: cannot allocate memory or input device"); goto fail1; } aiptek->data = usb_buffer_alloc(usbdev, AIPTEK_PACKET_LENGTH, GFP_ATOMIC, &aiptek->data_dma); if (!aiptek->data) { warn("aiptek: cannot allocate usb buffer"); goto fail1; } aiptek->urb = usb_alloc_urb(0, GFP_KERNEL); if (!aiptek->urb) { warn("aiptek: cannot allocate urb"); goto fail2; } aiptek->inputdev = inputdev; aiptek->usbdev = usbdev; aiptek->ifnum = intf->altsetting[0].desc.bInterfaceNumber; aiptek->inDelay = 0; aiptek->endDelay = 0; aiptek->previousJitterable = 0; aiptek->lastMacro = -1; /* Set up the curSettings struct. Said struct contains the current * programmable parameters. The newSetting struct contains changes * the user makes to the settings via the sysfs interface. Those * changes are not "committed" to curSettings until the user * writes to the sysfs/.../execute file. */ aiptek->curSetting.pointerMode = AIPTEK_POINTER_EITHER_MODE; aiptek->curSetting.coordinateMode = AIPTEK_COORDINATE_ABSOLUTE_MODE; aiptek->curSetting.toolMode = AIPTEK_TOOL_BUTTON_PEN_MODE; aiptek->curSetting.xTilt = AIPTEK_TILT_DISABLE; aiptek->curSetting.yTilt = AIPTEK_TILT_DISABLE; aiptek->curSetting.mouseButtonLeft = AIPTEK_MOUSE_LEFT_BUTTON; aiptek->curSetting.mouseButtonMiddle = AIPTEK_MOUSE_MIDDLE_BUTTON; aiptek->curSetting.mouseButtonRight = AIPTEK_MOUSE_RIGHT_BUTTON; aiptek->curSetting.stylusButtonUpper = AIPTEK_STYLUS_UPPER_BUTTON; aiptek->curSetting.stylusButtonLower = AIPTEK_STYLUS_LOWER_BUTTON; aiptek->curSetting.jitterDelay = jitterDelay; aiptek->curSetting.programmableDelay = programmableDelay; /* Both structs should have equivalent settings */ aiptek->newSetting = aiptek->curSetting; /* Determine the usb devices' physical path. * Asketh not why we always pretend we're using "../input0", * but I suspect this will have to be refactored one * day if a single USB device can be a keyboard & a mouse * & a tablet, and the inputX number actually will tell * us something... */ usb_make_path(usbdev, aiptek->features.usbPath, sizeof(aiptek->features.usbPath)); strlcat(aiptek->features.usbPath, "/input0", sizeof(aiptek->features.usbPath)); /* Set up client data, pointers to open and close routines * for the input device. */ inputdev->name = "Aiptek"; inputdev->phys = aiptek->features.usbPath; usb_to_input_id(usbdev, &inputdev->id); inputdev->dev.parent = &intf->dev; input_set_drvdata(inputdev, aiptek); inputdev->open = aiptek_open; inputdev->close = aiptek_close; /* Now program the capacities of the tablet, in terms of being * an input device. */ for (i = 0; i < ARRAY_SIZE(eventTypes); ++i) __set_bit(eventTypes[i], inputdev->evbit); for (i = 0; i < ARRAY_SIZE(absEvents); ++i) __set_bit(absEvents[i], inputdev->absbit); for (i = 0; i < ARRAY_SIZE(relEvents); ++i) __set_bit(relEvents[i], inputdev->relbit); __set_bit(MSC_SERIAL, inputdev->mscbit); /* Set up key and button codes */ for (i = 0; i < ARRAY_SIZE(buttonEvents); ++i) __set_bit(buttonEvents[i], inputdev->keybit); for (i = 0; i < ARRAY_SIZE(macroKeyEvents); ++i) __set_bit(macroKeyEvents[i], inputdev->keybit); /* * Program the input device coordinate capacities. We do not yet * know what maximum X, Y, and Z values are, so we're putting fake * values in. Later, we'll ask the tablet to put in the correct * values. */ input_set_abs_params(inputdev, ABS_X, 0, 2999, 0, 0); input_set_abs_params(inputdev, ABS_Y, 0, 2249, 0, 0); input_set_abs_params(inputdev, ABS_PRESSURE, 0, 511, 0, 0); input_set_abs_params(inputdev, ABS_TILT_X, AIPTEK_TILT_MIN, AIPTEK_TILT_MAX, 0, 0); input_set_abs_params(inputdev, ABS_TILT_Y, AIPTEK_TILT_MIN, AIPTEK_TILT_MAX, 0, 0); input_set_abs_params(inputdev, ABS_WHEEL, AIPTEK_WHEEL_MIN, AIPTEK_WHEEL_MAX - 1, 0, 0); endpoint = &intf->altsetting[0].endpoint[0].desc; /* Go set up our URB, which is called when the tablet receives * input. */ usb_fill_int_urb(aiptek->urb, aiptek->usbdev, usb_rcvintpipe(aiptek->usbdev, endpoint->bEndpointAddress), aiptek->data, 8, aiptek_irq, aiptek, endpoint->bInterval); aiptek->urb->transfer_dma = aiptek->data_dma; aiptek->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; /* Program the tablet. This sets the tablet up in the mode * specified in newSetting, and also queries the tablet's * physical capacities. * * Sanity check: if a tablet doesn't like the slow programmatic * delay, we often get sizes of 0x0. Let's use that as an indicator * to try faster delays, up to 25 ms. If that logic fails, well, you'll * have to explain to us how your tablet thinks it's 0x0, and yet that's * not an error :-) */ for (i = 0; i < ARRAY_SIZE(speeds); ++i) { aiptek->curSetting.programmableDelay = speeds[i]; (void)aiptek_program_tablet(aiptek); if (aiptek->inputdev->absmax[ABS_X] > 0) { info("input: Aiptek using %d ms programming speed\n", aiptek->curSetting.programmableDelay); break; } } /* Murphy says that some day someone will have a tablet that fails the above test. That's you, Frederic Rodrigo */ if (i == ARRAY_SIZE(speeds)) { info("input: Aiptek tried all speeds, no sane response"); goto fail2; } /* Associate this driver's struct with the usb interface. */ usb_set_intfdata(intf, aiptek); /* Set up the sysfs files */ err = sysfs_create_group(&intf->dev.kobj, &aiptek_attribute_group); if (err) { warn("aiptek: cannot create sysfs group err: %d", err); goto fail3; } /* Register the tablet as an Input Device */ err = input_register_device(aiptek->inputdev); if (err) { warn("aiptek: input_register_device returned err: %d", err); goto fail4; } return 0; fail4: sysfs_remove_group(&intf->dev.kobj, &aiptek_attribute_group); fail3: usb_free_urb(aiptek->urb); fail2: usb_buffer_free(usbdev, AIPTEK_PACKET_LENGTH, aiptek->data, aiptek->data_dma); fail1: usb_set_intfdata(intf, NULL); input_free_device(inputdev); kfree(aiptek); return err;}/*********************************************************************** * Deal with tablet disconnecting from the system. */static void aiptek_disconnect(struct usb_interface *intf){ struct aiptek *aiptek = usb_get_intfdata(intf); /* Disassociate driver's struct with usb interface */ usb_set_intfdata(intf, NULL); if (aiptek != NULL) { /* Free & unhook everything from the system. */ usb_kill_urb(aiptek->urb); input_unregister_device(aiptek->inputdev); sysfs_remove_group(&intf->dev.kobj, &aiptek_attribute_group); usb_free_urb(aiptek->urb); usb_buffer_free(interface_to_usbdev(intf), AIPTEK_PACKET_LENGTH, aiptek->data, aiptek->data_dma); kfree(aiptek); }}static struct usb_driver aiptek_driver = { .name = "aiptek", .probe = aiptek_probe, .disconnect = aiptek_disconnect, .id_table = aiptek_ids,};static int __init aiptek_init(void){ int result = usb_register(&aiptek_driver); if (result == 0) { info(DRIVER_VERSION ": " DRIVER_AUTHOR); info(DRIVER_DESC); } return result;}static void __exit aiptek_exit(void){ usb_deregister(&aiptek_driver);}MODULE_AUTHOR(DRIVER_AUTHOR);MODULE_DESCRIPTION(DRIVER_DESC);MODULE_LICENSE("GPL");module_param(programmableDelay, int, 0);MODULE_PARM_DESC(programmableDelay, "delay used during tablet programming");module_param(jitterDelay, int, 0);MODULE_PARM_DESC(jitterDelay, "stylus/mouse settlement delay");module_init(aiptek_init);module_exit(aiptek_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -