📄 aiptek.c
字号:
break; default: s = "unknown"; break; } return snprintf(buf, PAGE_SIZE, "%s\n", s);}static ssize_tstore_tabletMouseMiddle(struct device *dev, const char *buf, size_t count){ struct aiptek *aiptek = dev_get_drvdata(dev); if (aiptek == NULL) return 0; if (strcmp(buf, "left") == 0) { aiptek->newSetting.mouseButtonMiddle = AIPTEK_MOUSE_LEFT_BUTTON; } else if (strcmp(buf, "middle") == 0) { aiptek->newSetting.mouseButtonMiddle = AIPTEK_MOUSE_MIDDLE_BUTTON; } else if (strcmp(buf, "right") == 0) { aiptek->newSetting.mouseButtonMiddle = AIPTEK_MOUSE_RIGHT_BUTTON; } return count;}static DEVICE_ATTR(mouse_middle, S_IRUGO | S_IWUGO, show_tabletMouseMiddle, store_tabletMouseMiddle);/*********************************************************************** * support routines for the 'mouse_right' file. Note that this file * both displays current setting and allows for setting changing. */static ssize_t show_tabletMouseRight(struct device *dev, char *buf){ struct aiptek *aiptek = dev_get_drvdata(dev); char *s; if (aiptek == NULL) return 0; switch (aiptek->curSetting.mouseButtonRight) { case AIPTEK_MOUSE_LEFT_BUTTON: s = "left"; break; case AIPTEK_MOUSE_MIDDLE_BUTTON: s = "middle"; break; case AIPTEK_MOUSE_RIGHT_BUTTON: s = "right"; break; default: s = "unknown"; break; } return snprintf(buf, PAGE_SIZE, "%s\n", s);}static ssize_tstore_tabletMouseRight(struct device *dev, const char *buf, size_t count){ struct aiptek *aiptek = dev_get_drvdata(dev); if (aiptek == NULL) return 0; if (strcmp(buf, "left") == 0) { aiptek->newSetting.mouseButtonRight = AIPTEK_MOUSE_LEFT_BUTTON; } else if (strcmp(buf, "middle") == 0) { aiptek->newSetting.mouseButtonRight = AIPTEK_MOUSE_MIDDLE_BUTTON; } else if (strcmp(buf, "right") == 0) { aiptek->newSetting.mouseButtonRight = AIPTEK_MOUSE_RIGHT_BUTTON; } return count;}static DEVICE_ATTR(mouse_right, S_IRUGO | S_IWUGO, show_tabletMouseRight, store_tabletMouseRight);/*********************************************************************** * support routines for the 'wheel' file. Note that this file * both displays current setting and allows for setting changing. */static ssize_t show_tabletWheel(struct device *dev, char *buf){ struct aiptek *aiptek = dev_get_drvdata(dev); if (aiptek == NULL) return 0; if (aiptek->curSetting.wheel == AIPTEK_WHEEL_DISABLE) { return snprintf(buf, PAGE_SIZE, "disable\n"); } else { return snprintf(buf, PAGE_SIZE, "%d\n", aiptek->curSetting.wheel); }}static ssize_tstore_tabletWheel(struct device *dev, const char *buf, size_t count){ struct aiptek *aiptek = dev_get_drvdata(dev); if (aiptek == NULL) return 0; 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, char *buf){ struct aiptek *aiptek = dev_get_drvdata(dev); if (aiptek == NULL) return 0; /* 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, const char *buf, size_t count){ struct aiptek *aiptek = dev_get_drvdata(dev); if (aiptek == NULL) return 0; /* 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, char *buf){ struct aiptek *aiptek = dev_get_drvdata(dev); if (aiptek == NULL) return 0; 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, char *buf){ struct aiptek *aiptek = dev_get_drvdata(dev); if (aiptek == NULL) return 0; 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, char *buf){ struct aiptek *aiptek = dev_get_drvdata(dev); if (aiptek == NULL) return 0; return snprintf(buf, PAGE_SIZE, "%04x\n", aiptek->features.firmwareCode);}static DEVICE_ATTR(firmware_code, S_IRUGO, show_firmwareCode, NULL);/*********************************************************************** * This routine removes all existing sysfs files managed by this device * driver. */static void aiptek_delete_files(struct device *dev){ device_remove_file(dev, &dev_attr_size); device_remove_file(dev, &dev_attr_product_id); device_remove_file(dev, &dev_attr_vendor_id); device_remove_file(dev, &dev_attr_vendor); device_remove_file(dev, &dev_attr_product); device_remove_file(dev, &dev_attr_pointer_mode); device_remove_file(dev, &dev_attr_coordinate_mode); device_remove_file(dev, &dev_attr_tool_mode); device_remove_file(dev, &dev_attr_xtilt); device_remove_file(dev, &dev_attr_ytilt); device_remove_file(dev, &dev_attr_jitter); device_remove_file(dev, &dev_attr_delay); device_remove_file(dev, &dev_attr_input_path); device_remove_file(dev, &dev_attr_event_count); device_remove_file(dev, &dev_attr_diagnostic); device_remove_file(dev, &dev_attr_odm_code); device_remove_file(dev, &dev_attr_model_code); device_remove_file(dev, &dev_attr_firmware_code); device_remove_file(dev, &dev_attr_stylus_lower); device_remove_file(dev, &dev_attr_stylus_upper); device_remove_file(dev, &dev_attr_mouse_left); device_remove_file(dev, &dev_attr_mouse_middle); device_remove_file(dev, &dev_attr_mouse_right); device_remove_file(dev, &dev_attr_wheel); device_remove_file(dev, &dev_attr_execute);}/*********************************************************************** * This routine creates the sysfs files managed by this device * driver. */static int aiptek_add_files(struct device *dev){ int ret; if ((ret = device_create_file(dev, &dev_attr_size)) || (ret = device_create_file(dev, &dev_attr_product_id)) || (ret = device_create_file(dev, &dev_attr_vendor_id)) || (ret = device_create_file(dev, &dev_attr_vendor)) || (ret = device_create_file(dev, &dev_attr_product)) || (ret = device_create_file(dev, &dev_attr_pointer_mode)) || (ret = device_create_file(dev, &dev_attr_coordinate_mode)) || (ret = device_create_file(dev, &dev_attr_tool_mode)) || (ret = device_create_file(dev, &dev_attr_xtilt)) || (ret = device_create_file(dev, &dev_attr_ytilt)) || (ret = device_create_file(dev, &dev_attr_jitter)) || (ret = device_create_file(dev, &dev_attr_delay)) || (ret = device_create_file(dev, &dev_attr_input_path)) || (ret = device_create_file(dev, &dev_attr_event_count)) || (ret = device_create_file(dev, &dev_attr_diagnostic)) || (ret = device_create_file(dev, &dev_attr_odm_code)) || (ret = device_create_file(dev, &dev_attr_model_code)) || (ret = device_create_file(dev, &dev_attr_firmware_code)) || (ret = device_create_file(dev, &dev_attr_stylus_lower)) || (ret = device_create_file(dev, &dev_attr_stylus_upper)) || (ret = device_create_file(dev, &dev_attr_mouse_left)) || (ret = device_create_file(dev, &dev_attr_mouse_middle)) || (ret = device_create_file(dev, &dev_attr_mouse_right)) || (ret = device_create_file(dev, &dev_attr_wheel)) || (ret = device_create_file(dev, &dev_attr_execute))) { err("aiptek: killing own sysfs device files\n"); aiptek_delete_files(dev); } return ret;}/*********************************************************************** * 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; struct input_handle *inputhandle; struct list_head *node, *next; char path[64 + 1]; 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 }; /* 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; if ((aiptek = kmalloc(sizeof(struct aiptek), GFP_KERNEL)) == NULL) return -ENOMEM; memset(aiptek, 0, sizeof(struct aiptek)); aiptek->data = usb_buffer_alloc(usbdev, AIPTEK_PACKET_LENGTH, SLAB_ATOMIC, &aiptek->data_dma); if (aiptek->data == NULL) { kfree(aiptek); return -ENOMEM; } aiptek->urb = usb_alloc_urb(0, GFP_KERNEL); if (aiptek->urb == NULL) { usb_buffer_free(usbdev, AIPTEK_PACKET_LENGTH, aiptek->data, aiptek->data_dma); kfree(aiptek); return -ENOMEM; } /* 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 */ memcpy(&aiptek->newSetting, &aiptek->curSetting, sizeof(struct aiptek_settings)); /* Now program the capacities of the tablet, in terms of being * an input device. */ aiptek->inputdev.evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_REL) | BIT(EV_MSC); aiptek->inputdev.absbit[0] |= (BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_PRESSURE) | BIT(ABS_TILT_X) | BIT(ABS_TILT_Y) | BIT(ABS_WHEEL) | BIT(ABS_MISC)); aiptek->inputdev.relbit[0] |= (BIT(REL_X) | BIT(REL_Y) | BIT(REL_WHEEL) | BIT(REL_MISC)); aiptek->inputdev.keybit[LONG(BTN_LEFT)] |= (BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE)); aiptek->inputdev.keybit[LONG(BTN_DIGI)] |= (BIT(BTN_TOOL_PEN) | BIT(BTN_TOOL_RUBBER) | BIT(BTN_TOOL_PENCIL) | BIT(BTN_TOOL_AIRBRUSH) | BIT(BTN_TOOL_BRUSH) | BIT(BTN_TOOL_MOUSE) | BIT(BTN_TOOL_LENS) | BIT(BTN_TOUCH) | BIT(BTN_STYLUS) | BIT(BTN_STYLUS2)); aiptek->inputdev.mscbit[0] = BIT(MSC_SERIAL); /* Programming the tablet macro keys needs to be done with a for loop * as the keycodes are discontiguous. */ for (i = 0; i < sizeof(macroKeyEvents) / sizeof(macroKeyEvents[0]); ++i) set_bit(macroKeyEvents[i], aiptek->inputdev.keybit); /* Set up client data, pointers to open and close routines * for the input device. */ aiptek->inputdev.private = aiptek; aiptek->inputdev.open = aiptek_open; aiptek->inputdev.close = aiptek_close; /* 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... */ if (usb_make_path(usbdev, path, 64) > 0) sprintf(aiptek->features.usbPath, "%s/input0", path); /* 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.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -