📄 aiptek.c
字号:
*/ if (aiptek->previousToolMode != aiptek->curSetting.toolMode) { input_report_key(inputdev, aiptek->previousToolMode, 0); input_report_key(inputdev, aiptek->curSetting.toolMode, 1); aiptek->previousToolMode = aiptek->curSetting.toolMode; } input_report_key(inputdev, macroKeyEvents[macro], 1); input_report_abs(inputdev, ABS_MISC, 1 | AIPTEK_REPORT_TOOL_UNKNOWN); input_sync(inputdev); } else { dbg("Unknown report %d", data[0]); } /* Jitter may occur when the user presses a button on the stlyus * or the mouse. What we do to prevent that is wait 'x' milliseconds * following a 'jitterable' event, which should give the hand some time * stabilize itself. * * We just introduced aiptek->previousJitterable to carry forth the * notion that jitter occurs when the button state changes from on to off: * a person drawing, holding a button down is not subject to jittering. * With that in mind, changing from upper button depressed to lower button * WILL transition through a jitter delay. */ if (aiptek->previousJitterable != jitterable && aiptek->curSetting.jitterDelay != 0 && aiptek->inDelay != 1) { aiptek->endDelay = jiffies + ((aiptek->curSetting.jitterDelay * HZ) / 1000); aiptek->inDelay = 1; } aiptek->previousJitterable = jitterable;exit: retval = usb_submit_urb(urb, GFP_ATOMIC); if (retval != 0) { err("%s - usb_submit_urb failed with result %d", __FUNCTION__, retval); }}/*********************************************************************** * These are the USB id's known so far. We do not identify them to * specific Aiptek model numbers, because there has been overlaps, * use, and reuse of id's in existing models. Certain models have * been known to use more than one ID, indicative perhaps of * manufacturing revisions. In any event, we consider these * IDs to not be model-specific nor unique. */static const struct usb_device_id aiptek_ids[] = { {USB_DEVICE(USB_VENDOR_ID_AIPTEK, 0x01)}, {USB_DEVICE(USB_VENDOR_ID_AIPTEK, 0x10)}, {USB_DEVICE(USB_VENDOR_ID_AIPTEK, 0x20)}, {USB_DEVICE(USB_VENDOR_ID_AIPTEK, 0x21)}, {USB_DEVICE(USB_VENDOR_ID_AIPTEK, 0x22)}, {USB_DEVICE(USB_VENDOR_ID_AIPTEK, 0x23)}, {USB_DEVICE(USB_VENDOR_ID_AIPTEK, 0x24)}, {}};MODULE_DEVICE_TABLE(usb, aiptek_ids);/*********************************************************************** * Open an instance of the tablet driver. */static int aiptek_open(struct input_dev *inputdev){ struct aiptek *aiptek = input_get_drvdata(inputdev); aiptek->urb->dev = aiptek->usbdev; if (usb_submit_urb(aiptek->urb, GFP_KERNEL) != 0) return -EIO; return 0;}/*********************************************************************** * Close an instance of the tablet driver. */static void aiptek_close(struct input_dev *inputdev){ struct aiptek *aiptek = input_get_drvdata(inputdev); usb_kill_urb(aiptek->urb);}/*********************************************************************** * aiptek_set_report and aiptek_get_report() are borrowed from Linux 2.4.x, * where they were known as usb_set_report and usb_get_report. */static intaiptek_set_report(struct aiptek *aiptek, unsigned char report_type, unsigned char report_id, void *buffer, int size){ return usb_control_msg(aiptek->usbdev, usb_sndctrlpipe(aiptek->usbdev, 0), USB_REQ_SET_REPORT, USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, (report_type << 8) + report_id, aiptek->ifnum, buffer, size, 5000);}static intaiptek_get_report(struct aiptek *aiptek, unsigned char report_type, unsigned char report_id, void *buffer, int size){ return usb_control_msg(aiptek->usbdev, usb_rcvctrlpipe(aiptek->usbdev, 0), USB_REQ_GET_REPORT, USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, (report_type << 8) + report_id, aiptek->ifnum, buffer, size, 5000);}/*********************************************************************** * Send a command to the tablet. */static intaiptek_command(struct aiptek *aiptek, unsigned char command, unsigned char data){ const int sizeof_buf = 3 * sizeof(u8); int ret; u8 *buf; buf = kmalloc(sizeof_buf, GFP_KERNEL); if (!buf) return -ENOMEM; buf[0] = 2; buf[1] = command; buf[2] = data; if ((ret = aiptek_set_report(aiptek, 3, 2, buf, sizeof_buf)) != sizeof_buf) { dbg("aiptek_program: failed, tried to send: 0x%02x 0x%02x", command, data); } kfree(buf); return ret < 0 ? ret : 0;}/*********************************************************************** * Retrieve information from the tablet. Querying info is defined as first * sending the {command,data} sequence as a command, followed by a wait * (aka, "programmaticDelay") and then a "read" request. */static intaiptek_query(struct aiptek *aiptek, unsigned char command, unsigned char data){ const int sizeof_buf = 3 * sizeof(u8); int ret; u8 *buf; buf = kmalloc(sizeof_buf, GFP_KERNEL); if (!buf) return -ENOMEM; buf[0] = 2; buf[1] = command; buf[2] = data; if (aiptek_command(aiptek, command, data) != 0) { kfree(buf); return -EIO; } msleep(aiptek->curSetting.programmableDelay); if ((ret = aiptek_get_report(aiptek, 3, 2, buf, sizeof_buf)) != sizeof_buf) { dbg("aiptek_query failed: returned 0x%02x 0x%02x 0x%02x", buf[0], buf[1], buf[2]); ret = -EIO; } else { ret = le16_to_cpu(get_unaligned((__le16 *) (buf + 1))); } kfree(buf); return ret;}/*********************************************************************** * Program the tablet into either absolute or relative mode. * We also get information about the tablet's size. */static int aiptek_program_tablet(struct aiptek *aiptek){ int ret; /* Execute Resolution500LPI */ if ((ret = aiptek_command(aiptek, 0x18, 0x04)) < 0) return ret; /* Query getModelCode */ if ((ret = aiptek_query(aiptek, 0x02, 0x00)) < 0) return ret; aiptek->features.modelCode = ret & 0xff; /* Query getODMCode */ if ((ret = aiptek_query(aiptek, 0x03, 0x00)) < 0) return ret; aiptek->features.odmCode = ret; /* Query getFirmwareCode */ if ((ret = aiptek_query(aiptek, 0x04, 0x00)) < 0) return ret; aiptek->features.firmwareCode = ret; /* Query getXextension */ if ((ret = aiptek_query(aiptek, 0x01, 0x00)) < 0) return ret; aiptek->inputdev->absmin[ABS_X] = 0; aiptek->inputdev->absmax[ABS_X] = ret - 1; /* Query getYextension */ if ((ret = aiptek_query(aiptek, 0x01, 0x01)) < 0) return ret; aiptek->inputdev->absmin[ABS_Y] = 0; aiptek->inputdev->absmax[ABS_Y] = ret - 1; /* Query getPressureLevels */ if ((ret = aiptek_query(aiptek, 0x08, 0x00)) < 0) return ret; aiptek->inputdev->absmin[ABS_PRESSURE] = 0; aiptek->inputdev->absmax[ABS_PRESSURE] = ret - 1; /* Depending on whether we are in absolute or relative mode, we will * do a switchToTablet(absolute) or switchToMouse(relative) command. */ if (aiptek->curSetting.coordinateMode == AIPTEK_COORDINATE_ABSOLUTE_MODE) { /* Execute switchToTablet */ if ((ret = aiptek_command(aiptek, 0x10, 0x01)) < 0) { return ret; } } else { /* Execute switchToMouse */ if ((ret = aiptek_command(aiptek, 0x10, 0x00)) < 0) { return ret; } } /* Enable the macro keys */ if ((ret = aiptek_command(aiptek, 0x11, 0x02)) < 0) return ret;#if 0 /* Execute FilterOn */ if ((ret = aiptek_command(aiptek, 0x17, 0x00)) < 0) return ret;#endif /* Execute AutoGainOn */ if ((ret = aiptek_command(aiptek, 0x12, 0xff)) < 0) return ret; /* Reset the eventCount, so we track events from last (re)programming */ aiptek->diagnostic = AIPTEK_DIAGNOSTIC_NA; aiptek->eventCount = 0; return 0;}/*********************************************************************** * Sysfs functions. Sysfs prefers that individually-tunable parameters * exist in their separate pseudo-files. Summary data that is immutable * may exist in a singular file so long as you don't define a writeable * interface. *//*********************************************************************** * support the 'size' file -- display support */static ssize_t show_tabletSize(struct device *dev, struct device_attribute *attr, char *buf){ struct aiptek *aiptek = dev_get_drvdata(dev); return snprintf(buf, PAGE_SIZE, "%dx%d\n", aiptek->inputdev->absmax[ABS_X] + 1, aiptek->inputdev->absmax[ABS_Y] + 1);}/* These structs define the sysfs files, param #1 is the name of the * file, param 2 is the file permissions, param 3 & 4 are to the * output generator and input parser routines. Absence of a routine is * permitted -- it only means can't either 'cat' the file, or send data * to it. */static DEVICE_ATTR(size, S_IRUGO, show_tabletSize, NULL);/*********************************************************************** * support routines for the 'pointer_mode' file. Note that this file * both displays current setting and allows reprogramming. */static struct aiptek_map pointer_mode_map[] = { { "stylus", AIPTEK_POINTER_ONLY_STYLUS_MODE }, { "mouse", AIPTEK_POINTER_ONLY_MOUSE_MODE }, { "either", AIPTEK_POINTER_EITHER_MODE }, { NULL, AIPTEK_INVALID_VALUE }};static ssize_t show_tabletPointerMode(struct device *dev, struct device_attribute *attr, char *buf){ struct aiptek *aiptek = dev_get_drvdata(dev); return snprintf(buf, PAGE_SIZE, "%s\n", map_val_to_str(pointer_mode_map, aiptek->curSetting.pointerMode));}static ssize_tstore_tabletPointerMode(struct device *dev, struct device_attribute *attr, const char *buf, size_t count){ struct aiptek *aiptek = dev_get_drvdata(dev); int new_mode = map_str_to_val(pointer_mode_map, buf, count); if (new_mode == AIPTEK_INVALID_VALUE) return -EINVAL; aiptek->newSetting.pointerMode = new_mode; return count;}static DEVICE_ATTR(pointer_mode, S_IRUGO | S_IWUGO, show_tabletPointerMode, store_tabletPointerMode);/*********************************************************************** * support routines for the 'coordinate_mode' file. Note that this file * both displays current setting and allows reprogramming. */static struct aiptek_map coordinate_mode_map[] = { { "absolute", AIPTEK_COORDINATE_ABSOLUTE_MODE }, { "relative", AIPTEK_COORDINATE_RELATIVE_MODE }, { NULL, AIPTEK_INVALID_VALUE }};static ssize_t show_tabletCoordinateMode(struct device *dev, struct device_attribute *attr, char *buf){ struct aiptek *aiptek = dev_get_drvdata(dev); return snprintf(buf, PAGE_SIZE, "%s\n", map_val_to_str(coordinate_mode_map, aiptek->curSetting.coordinateMode));}static ssize_tstore_tabletCoordinateMode(struct device *dev, struct device_attribute *attr, const char *buf, size_t count){ struct aiptek *aiptek = dev_get_drvdata(dev); int new_mode = map_str_to_val(coordinate_mode_map, buf, count); if (new_mode == AIPTEK_INVALID_VALUE) return -EINVAL; aiptek->newSetting.coordinateMode = new_mode; return count;}static DEVICE_ATTR(coordinate_mode, S_IRUGO | S_IWUGO, show_tabletCoordinateMode, store_tabletCoordinateMode);/*********************************************************************** * support routines for the 'tool_mode' file. Note that this file * both displays current setting and allows reprogramming. */static struct aiptek_map tool_mode_map[] = { { "mouse", AIPTEK_TOOL_BUTTON_MOUSE_MODE }, { "eraser", AIPTEK_TOOL_BUTTON_ERASER_MODE }, { "pencil", AIPTEK_TOOL_BUTTON_PENCIL_MODE }, { "pen", AIPTEK_TOOL_BUTTON_PEN_MODE }, { "brush", AIPTEK_TOOL_BUTTON_BRUSH_MODE }, { "airbrush", AIPTEK_TOOL_BUTTON_AIRBRUSH_MODE }, { "lens", AIPTEK_TOOL_BUTTON_LENS_MODE }, { NULL, AIPTEK_INVALID_VALUE }};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -