diff options
Diffstat (limited to 'drivers/hid')
-rw-r--r-- | drivers/hid/Kconfig | 79 | ||||
-rw-r--r-- | drivers/hid/Makefile | 3 | ||||
-rw-r--r-- | drivers/hid/hid-core.c | 4 | ||||
-rw-r--r-- | drivers/hid/hid-ids.h | 8 | ||||
-rw-r--r-- | drivers/hid/hid-ntrig.c | 526 | ||||
-rw-r--r-- | drivers/hid/hid-picolcd.c | 2631 | ||||
-rw-r--r-- | drivers/hid/hid-prodikeys.c | 910 | ||||
-rw-r--r-- | drivers/hid/hid-roccat-kone.c | 994 | ||||
-rw-r--r-- | drivers/hid/hid-roccat-kone.h | 224 | ||||
-rw-r--r-- | drivers/hid/usbhid/hid-core.c | 1 |
10 files changed, 5371 insertions, 9 deletions
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 4ea926a21bc..339c1eaa55a 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -106,6 +106,21 @@ config HID_CHICONY ---help--- Support for Chicony Tactical pad. +config HID_PRODIKEYS + tristate "Prodikeys PC-MIDI Keyboard support" + depends on USB_HID && SND + select SND_RAWMIDI + ---help--- + Support for Prodikeys PC-MIDI Keyboard device support. + Say Y here to enable support for this device. + - Prodikeys PC-MIDI keyboard. + The Prodikeys PC-MIDI acts as a USB Audio device, with one MIDI + input and one MIDI output. These MIDI jacks appear as + a sound "card" in the ALSA sound system. + Note: if you say N here, this device will still function as a basic + multimedia keyboard, but will lack support for the musical keyboard + and some additional multimedia keys. + config HID_CYPRESS tristate "Cypress" if EMBEDDED depends on USB_HID @@ -274,12 +289,76 @@ config HID_PETALYNX ---help--- Support for Petalynx Maxter remote control. +config HID_PICOLCD + tristate "PicoLCD (graphic version)" + depends on USB_HID + ---help--- + This provides support for Minibox PicoLCD devices, currently + only the graphical ones are supported. + + This includes support for the following device features: + - Keypad + - Switching between Firmware and Flash mode + - EEProm / Flash access (via debugfs) + Features selectively enabled: + - Framebuffer for monochrome 256x64 display + - Backlight control + - Contrast control + - General purpose outputs + Features that are not (yet) supported: + - IR + +config HID_PICOLCD_FB + bool "Framebuffer support" if EMBEDDED + default !EMBEDDED + depends on HID_PICOLCD + depends on HID_PICOLCD=FB || FB=y + select FB_DEFERRED_IO + select FB_SYS_FILLRECT + select FB_SYS_COPYAREA + select FB_SYS_IMAGEBLIT + select FB_SYS_FOPS + ---help--- + Provide access to PicoLCD's 256x64 monochrome display via a + frambuffer device. + +config HID_PICOLCD_BACKLIGHT + bool "Backlight control" if EMBEDDED + default !EMBEDDED + depends on HID_PICOLCD + depends on HID_PICOLCD=BACKLIGHT_CLASS_DEVICE || BACKLIGHT_CLASS_DEVICE=y + ---help--- + Provide access to PicoLCD's backlight control via backlight + class. + +config HID_PICOLCD_LCD + bool "Contrast control" if EMBEDDED + default !EMBEDDED + depends on HID_PICOLCD + depends on HID_PICOLCD=LCD_CLASS_DEVICE || LCD_CLASS_DEVICE=y + ---help--- + Provide access to PicoLCD's LCD contrast via lcd class. + +config HID_PICOLCD_LEDS + bool "GPO via leds class" if EMBEDDED + default !EMBEDDED + depends on HID_PICOLCD + depends on HID_PICOLCD=LEDS_CLASS || LEDS_CLASS=y + ---help--- + Provide access to PicoLCD's GPO pins via leds class. + config HID_QUANTA tristate "Quanta Optical Touch" depends on USB_HID ---help--- Support for Quanta Optical Touch dual-touch panels. +config HID_ROCCAT_KONE + tristate "Roccat Kone Mouse support" + depends on USB_HID + ---help--- + Support for Roccat Kone mouse. + config HID_SAMSUNG tristate "Samsung" if EMBEDDED depends on USB_HID diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index 2e196c734d2..22e47eaeea3 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -43,9 +43,12 @@ obj-$(CONFIG_HID_MONTEREY) += hid-monterey.o obj-$(CONFIG_HID_MOSART) += hid-mosart.o obj-$(CONFIG_HID_NTRIG) += hid-ntrig.o obj-$(CONFIG_HID_ORTEK) += hid-ortek.o +obj-$(CONFIG_HID_PRODIKEYS) += hid-prodikeys.o obj-$(CONFIG_HID_QUANTA) += hid-quanta.o obj-$(CONFIG_HID_PANTHERLORD) += hid-pl.o obj-$(CONFIG_HID_PETALYNX) += hid-petalynx.o +obj-$(CONFIG_HID_PICOLCD) += hid-picolcd.o +obj-$(CONFIG_HID_ROCCAT_KONE) += hid-roccat-kone.o obj-$(CONFIG_HID_SAMSUNG) += hid-samsung.o obj-$(CONFIG_HID_SMARTJOYPLUS) += hid-sjoy.o obj-$(CONFIG_HID_SONY) += hid-sony.o diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index ef492d3d52e..e10e314d38c 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1287,6 +1287,7 @@ static const struct hid_device_id hid_blacklist[] = { { HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION) }, { HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION_SOLAR) }, { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_TACTICAL_PAD) }, + { HID_USB_DEVICE(USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_PRODIKEYS_PCMIDI) }, { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1) }, { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2) }, { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_3) }, @@ -1326,6 +1327,8 @@ static const struct hid_device_id hid_blacklist[] = { { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACETRAVELLER) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACENAVIGATOR) }, + { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICOLCD) }, + { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICOLCD_BOOTLOADER) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE4K) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_LK6K) }, @@ -1337,6 +1340,7 @@ static const struct hid_device_id hid_blacklist[] = { { HID_USB_DEVICE(USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE) }, { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH) }, { HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN) }, + { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONE) }, { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) }, { HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 16c2f866821..9776896cc4f 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -156,6 +156,9 @@ #define USB_DEVICE_ID_CODEMERCS_IOW_FIRST 0x1500 #define USB_DEVICE_ID_CODEMERCS_IOW_LAST 0x15ff +#define USB_VENDOR_ID_CREATIVELABS 0x041e +#define USB_DEVICE_ID_PRODIKEYS_PCMIDI 0x2801 + #define USB_VENDOR_ID_CYGNAL 0x10c4 #define USB_DEVICE_ID_CYGNAL_RADIO_SI470X 0x818a @@ -354,6 +357,8 @@ #define USB_VENDOR_ID_MICROCHIP 0x04d8 #define USB_DEVICE_ID_PICKIT1 0x0032 #define USB_DEVICE_ID_PICKIT2 0x0033 +#define USB_DEVICE_ID_PICOLCD 0xc002 +#define USB_DEVICE_ID_PICOLCD_BOOTLOADER 0xf002 #define USB_VENDOR_ID_MICROSOFT 0x045e #define USB_DEVICE_ID_SIDEWINDER_GV 0x003b @@ -412,6 +417,9 @@ #define USB_VENDOR_ID_PRODIGE 0x05af #define USB_DEVICE_ID_PRODIGE_CORDLESS 0x3062 +#define USB_VENDOR_ID_ROCCAT 0x1e7d +#define USB_DEVICE_ID_ROCCAT_KONE 0x2ced + #define USB_VENDOR_ID_SAITEK 0x06a3 #define USB_DEVICE_ID_SAITEK_RUMBLEPAD 0xff17 diff --git a/drivers/hid/hid-ntrig.c b/drivers/hid/hid-ntrig.c index 4777bbfa1cc..b6b0caeeac5 100644 --- a/drivers/hid/hid-ntrig.c +++ b/drivers/hid/hid-ntrig.c @@ -24,6 +24,34 @@ #define NTRIG_DUPLICATE_USAGES 0x001 +static unsigned int min_width; +module_param(min_width, uint, 0644); +MODULE_PARM_DESC(min_width, "Minimum touch contact width to accept."); + +static unsigned int min_height; +module_param(min_height, uint, 0644); +MODULE_PARM_DESC(min_height, "Minimum touch contact height to accept."); + +static unsigned int activate_slack = 1; +module_param(activate_slack, uint, 0644); +MODULE_PARM_DESC(activate_slack, "Number of touch frames to ignore at " + "the start of touch input."); + +static unsigned int deactivate_slack = 4; +module_param(deactivate_slack, uint, 0644); +MODULE_PARM_DESC(deactivate_slack, "Number of empty frames to ignore before " + "deactivating touch."); + +static unsigned int activation_width = 64; +module_param(activation_width, uint, 0644); +MODULE_PARM_DESC(activation_width, "Width threshold to immediately start " + "processing touch events."); + +static unsigned int activation_height = 32; +module_param(activation_height, uint, 0644); +MODULE_PARM_DESC(activation_height, "Height threshold to immediately start " + "processing touch events."); + struct ntrig_data { /* Incoming raw values for a single contact */ __u16 x, y, w, h; @@ -37,6 +65,309 @@ struct ntrig_data { __u8 mt_footer[4]; __u8 mt_foot_count; + + /* The current activation state. */ + __s8 act_state; + + /* Empty frames to ignore before recognizing the end of activity */ + __s8 deactivate_slack; + + /* Frames to ignore before acknowledging the start of activity */ + __s8 activate_slack; + + /* Minimum size contact to accept */ + __u16 min_width; + __u16 min_height; + + /* Threshold to override activation slack */ + __u16 activation_width; + __u16 activation_height; + + __u16 sensor_logical_width; + __u16 sensor_logical_height; + __u16 sensor_physical_width; + __u16 sensor_physical_height; +}; + + +static ssize_t show_phys_width(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct hid_device *hdev = container_of(dev, struct hid_device, dev); + struct ntrig_data *nd = hid_get_drvdata(hdev); + + return sprintf(buf, "%d\n", nd->sensor_physical_width); +} + +static DEVICE_ATTR(sensor_physical_width, S_IRUGO, show_phys_width, NULL); + +static ssize_t show_phys_height(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct hid_device *hdev = container_of(dev, struct hid_device, dev); + struct ntrig_data *nd = hid_get_drvdata(hdev); + + return sprintf(buf, "%d\n", nd->sensor_physical_height); +} + +static DEVICE_ATTR(sensor_physical_height, S_IRUGO, show_phys_height, NULL); + +static ssize_t show_log_width(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct hid_device *hdev = container_of(dev, struct hid_device, dev); + struct ntrig_data *nd = hid_get_drvdata(hdev); + + return sprintf(buf, "%d\n", nd->sensor_logical_width); +} + +static DEVICE_ATTR(sensor_logical_width, S_IRUGO, show_log_width, NULL); + +static ssize_t show_log_height(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct hid_device *hdev = container_of(dev, struct hid_device, dev); + struct ntrig_data *nd = hid_get_drvdata(hdev); + + return sprintf(buf, "%d\n", nd->sensor_logical_height); +} + +static DEVICE_ATTR(sensor_logical_height, S_IRUGO, show_log_height, NULL); + +static ssize_t show_min_width(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct hid_device *hdev = container_of(dev, struct hid_device, dev); + struct ntrig_data *nd = hid_get_drvdata(hdev); + + return sprintf(buf, "%d\n", nd->min_width * + nd->sensor_physical_width / + nd->sensor_logical_width); +} + +static ssize_t set_min_width(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct hid_device *hdev = container_of(dev, struct hid_device, dev); + struct ntrig_data *nd = hid_get_drvdata(hdev); + + unsigned long val; + + if (strict_strtoul(buf, 0, &val)) + return -EINVAL; + + if (val > nd->sensor_physical_width) + return -EINVAL; + + nd->min_width = val * nd->sensor_logical_width / + nd->sensor_physical_width; + + return count; +} + +static DEVICE_ATTR(min_width, S_IWUSR | S_IRUGO, show_min_width, set_min_width); + +static ssize_t show_min_height(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct hid_device *hdev = container_of(dev, struct hid_device, dev); + struct ntrig_data *nd = hid_get_drvdata(hdev); + + return sprintf(buf, "%d\n", nd->min_height * + nd->sensor_physical_height / + nd->sensor_logical_height); +} + +static ssize_t set_min_height(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct hid_device *hdev = container_of(dev, struct hid_device, dev); + struct ntrig_data *nd = hid_get_drvdata(hdev); + + unsigned long val; + + if (strict_strtoul(buf, 0, &val)) + return -EINVAL; + + if (val > nd->sensor_physical_height) + return -EINVAL; + + nd->min_height = val * nd->sensor_logical_height / + nd->sensor_physical_height; + + return count; +} + +static DEVICE_ATTR(min_height, S_IWUSR | S_IRUGO, show_min_height, + set_min_height); + +static ssize_t show_activate_slack(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct hid_device *hdev = container_of(dev, struct hid_device, dev); + struct ntrig_data *nd = hid_get_drvdata(hdev); + + return sprintf(buf, "%d\n", nd->activate_slack); +} + +static ssize_t set_activate_slack(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct hid_device *hdev = container_of(dev, struct hid_device, dev); + struct ntrig_data *nd = hid_get_drvdata(hdev); + + unsigned long val; + + if (strict_strtoul(buf, 0, &val)) + return -EINVAL; + + if (val > 0x7f) + return -EINVAL; + + nd->activate_slack = val; + + return count; +} + +static DEVICE_ATTR(activate_slack, S_IWUSR | S_IRUGO, show_activate_slack, + set_activate_slack); + +static ssize_t show_activation_width(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct hid_device *hdev = container_of(dev, struct hid_device, dev); + struct ntrig_data *nd = hid_get_drvdata(hdev); + + return sprintf(buf, "%d\n", nd->activation_width * + nd->sensor_physical_width / + nd->sensor_logical_width); +} + +static ssize_t set_activation_width(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct hid_device *hdev = container_of(dev, struct hid_device, dev); + struct ntrig_data *nd = hid_get_drvdata(hdev); + + unsigned long val; + + if (strict_strtoul(buf, 0, &val)) + return -EINVAL; + + if (val > nd->sensor_physical_width) + return -EINVAL; + + nd->activation_width = val * nd->sensor_logical_width / + nd->sensor_physical_width; + + return count; +} + +static DEVICE_ATTR(activation_width, S_IWUSR | S_IRUGO, show_activation_width, + set_activation_width); + +static ssize_t show_activation_height(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct hid_device *hdev = container_of(dev, struct hid_device, dev); + struct ntrig_data *nd = hid_get_drvdata(hdev); + + return sprintf(buf, "%d\n", nd->activation_height * + nd->sensor_physical_height / + nd->sensor_logical_height); +} + +static ssize_t set_activation_height(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct hid_device *hdev = container_of(dev, struct hid_device, dev); + struct ntrig_data *nd = hid_get_drvdata(hdev); + + unsigned long val; + + if (strict_strtoul(buf, 0, &val)) + return -EINVAL; + + if (val > nd->sensor_physical_height) + return -EINVAL; + + nd->activation_height = val * nd->sensor_logical_height / + nd->sensor_physical_height; + + return count; +} + +static DEVICE_ATTR(activation_height, S_IWUSR | S_IRUGO, + show_activation_height, set_activation_height); + +static ssize_t show_deactivate_slack(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct hid_device *hdev = container_of(dev, struct hid_device, dev); + struct ntrig_data *nd = hid_get_drvdata(hdev); + + return sprintf(buf, "%d\n", -nd->deactivate_slack); +} + +static ssize_t set_deactivate_slack(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct hid_device *hdev = container_of(dev, struct hid_device, dev); + struct ntrig_data *nd = hid_get_drvdata(hdev); + + unsigned long val; + + if (strict_strtoul(buf, 0, &val)) + return -EINVAL; + + /* + * No more than 8 terminal frames have been observed so far + * and higher slack is highly likely to leave the single + * touch emulation stuck down. + */ + if (val > 7) + return -EINVAL; + + nd->deactivate_slack = -val; + + return count; +} + +static DEVICE_ATTR(deactivate_slack, S_IWUSR | S_IRUGO, show_deactivate_slack, + set_deactivate_slack); + +static struct attribute *sysfs_attrs[] = { + &dev_attr_sensor_physical_width.attr, + &dev_attr_sensor_physical_height.attr, + &dev_attr_sensor_logical_width.attr, + &dev_attr_sensor_logical_height.attr, + &dev_attr_min_height.attr, + &dev_attr_min_width.attr, + &dev_attr_activate_slack.attr, + &dev_attr_activation_width.attr, + &dev_attr_activation_height.attr, + &dev_attr_deactivate_slack.attr, + NULL +}; + +static struct attribute_group ntrig_attribute_group = { + .attrs = sysfs_attrs }; /* @@ -49,6 +380,8 @@ static int ntrig_input_mapping(struct hid_device *hdev, struct hid_input *hi, struct hid_field *field, struct hid_usage *usage, unsigned long **bit, int *max) { + struct ntrig_data *nd = hid_get_drvdata(hdev); + /* No special mappings needed for the pen and single touch */ if (field->physical) return 0; @@ -62,6 +395,21 @@ static int ntrig_input_mapping(struct hid_device *hdev, struct hid_input *hi, input_set_abs_params(hi->input, ABS_X, field->logical_minimum, field->logical_maximum, 0, 0); + + if (!nd->sensor_logical_width) { + nd->sensor_logical_width = + field->logical_maximum - + field->logical_minimum; + nd->sensor_physical_width = + field->physical_maximum - + field->physical_minimum; + nd->activation_width = activation_width * + nd->sensor_logical_width / + nd->sensor_physical_width; + nd->min_width = min_width * + nd->sensor_logical_width / + nd->sensor_physical_width; + } return 1; case HID_GD_Y: hid_map_usage(hi, usage, bit, max, @@ -69,6 +417,21 @@ static int ntrig_input_mapping(struct hid_device *hdev, struct hid_input *hi, input_set_abs_params(hi->input, ABS_Y, field->logical_minimum, field->logical_maximum, 0, 0); + + if (!nd->sensor_logical_height) { + nd->sensor_logical_height = + field->logical_maximum - + field->logical_minimum; + nd->sensor_physical_height = + field->physical_maximum - + field->physical_minimum; + nd->activation_height = activation_height * + nd->sensor_logical_height / + nd->sensor_physical_height; + nd->min_height = min_height * + nd->sensor_logical_height / + nd->sensor_physical_height; + } return 1; } return 0; @@ -201,20 +564,68 @@ static int ntrig_event (struct hid_device *hid, struct hid_field *field, if (nd->mt_foot_count != 4) break; - /* Pen activity signal, trigger end of touch. */ + /* Pen activity signal. */ if (nd->mt_footer[2]) { + /* + * When the pen deactivates touch, we see a + * bogus frame with ContactCount > 0. + * We can + * save a bit of work by ensuring act_state < 0 + * even if deactivation slack is turned off. + */ + nd->act_state = deactivate_slack - 1; nd->confidence = 0; break; } - /* If the contact was invalid */ - if (!(nd->confidence && nd->mt_footer[0]) - || nd->w <= 250 - || nd->h <= 190) { - nd->confidence = 0; + /* + * The first footer value indicates the presence of a + * finger. + */ + if (nd->mt_footer[0]) { + /* + * We do not want to process contacts under + * the size threshold, but do not want to + * ignore them for activation state + */ + if (nd->w < nd->min_width || + nd->h < nd->min_height) + nd->confidence = 0; + } else break; + + if (nd->act_state > 0) { + /* + * Contact meets the activation size threshold + */ + if (nd->w >= nd->activation_width && + nd->h >= nd->activation_height) { + if (nd->id) + /* + * first contact, activate now + */ + nd->act_state = 0; + else { + /* + * avoid corrupting this frame + * but ensure next frame will + * be active + */ + nd->act_state = 1; + break; + } + } else + /* + * Defer adjusting the activation state + * until the end of the frame. + */ + break; } + /* Discarding this contact */ + if (!nd->confidence) + break; + /* emit a normal (X, Y) for the first point only */ if (nd->id == 0) { /* @@ -227,8 +638,15 @@ static int ntrig_event (struct hid_device *hid, struct hid_field *field, input_event(input, EV_ABS, ABS_X, nd->x); input_event(input, EV_ABS, ABS_Y, nd->y); } + + /* Emit MT events */ input_event(input, EV_ABS, ABS_MT_POSITION_X, nd->x); input_event(input, EV_ABS, ABS_MT_POSITION_Y, nd->y); + + /* + * Translate from height and width to size + * and orientation. + */ if (nd->w > nd->h) { input_event(input, EV_ABS, ABS_MT_ORIENTATION, 1); @@ -248,12 +666,88 @@ static int ntrig_event (struct hid_device *hid, struct hid_field *field, break; case HID_DG_CONTACTCOUNT: /* End of a multitouch group */ - if (!nd->reading_mt) + if (!nd->reading_mt) /* Just to be sure */ break; nd->reading_mt = 0; - if (nd->first_contact_touch) { + + /* + * Activation state machine logic: + * + * Fundamental states: + * state > 0: Inactive + * state <= 0: Active + * state < -deactivate_slack: + * Pen termination of touch + * + * Specific values of interest + * state == activate_slack + * no valid input since the last reset + * + * state == 0 + * general operational state + * + * state == -deactivate_slack + * read sufficient empty frames to accept + * the end of input and reset + */ + + if (nd->act_state > 0) { /* Currently inactive */ + if (value) + /* + * Consider each live contact as + * evidence of intentional activity. + */ + nd->act_state = (nd->act_state > value) + ? nd->act_state - value + : 0; + else + /* + * Empty frame before we hit the + * activity threshold, reset. + */ + nd->act_state = nd->activate_slack; + + /* + * Entered this block inactive and no + * coordinates sent this frame, so hold off + * on button state. + */ + break; + } else { /* Currently active */ + if (value && nd->act_state >= + nd->deactivate_slack) + /* + * Live point: clear accumulated + * deactivation count. + */ + nd->act_state = 0; + else if (nd->act_state <= nd->deactivate_slack) + /* + * We've consumed the deactivation + * slack, time to deactivate and reset. + */ + nd->act_state = + nd->activate_slack; + else { /* Move towards deactivation */ + nd->act_state--; + break; + } + } + + if (nd->first_contact_touch && nd->act_state <= 0) { + /* + * Check to see if we're ready to start + * emitting touch events. + * + * Note: activation slack will decrease over + * the course of the frame, and it will be + * inconsistent from the start to the end of + * the frame. However if the frame starts + * with slack, first_contact_touch will still + * be 0 and we will not get to this point. + */ input_report_key(input, BTN_TOOL_DOUBLETAP, 1); input_report_key(input, BTN_TOUCH, 1); } else { @@ -263,7 +757,7 @@ static int ntrig_event (struct hid_device *hid, struct hid_field *field, break; default: - /* fallback to the generic hidinput handling */ + /* fall-back to the generic hidinput handling */ return 0; } } @@ -293,6 +787,16 @@ static int ntrig_probe(struct hid_device *hdev, const struct hid_device_id *id) } nd->reading_mt = 0; + nd->min_width = 0; + nd->min_height = 0; + nd->activate_slack = activate_slack; + nd->act_state = activate_slack; + nd->deactivate_slack = -deactivate_slack; + nd->sensor_logical_width = 0; + nd->sensor_logical_height = 0; + nd->sensor_physical_width = 0; + nd->sensor_physical_height = 0; + hid_set_drvdata(hdev, nd); ret = hid_parse(hdev); @@ -344,6 +848,8 @@ static int ntrig_probe(struct hid_device *hdev, const struct hid_device_id *id) if (report) usbhid_submit_report(hdev, report, USB_DIR_OUT); + ret = sysfs_create_group(&hdev->dev.kobj, + &ntrig_attribute_group); return 0; err_free: @@ -353,6 +859,8 @@ err_free: static void ntrig_remove(struct hid_device *hdev) { + sysfs_remove_group(&hdev->dev.kobj, + &ntrig_attribute_group); hid_hw_stop(hdev); kfree(hid_get_drvdata(hdev)); } diff --git a/drivers/hid/hid-picolcd.c b/drivers/hid/hid-picolcd.c new file mode 100644 index 00000000000..7aabf65c48e --- /dev/null +++ b/drivers/hid/hid-picolcd.c @@ -0,0 +1,2631 @@ +/*************************************************************************** + * Copyright (C) 2010 by Bruno Prémont <bonbons@linux-vserver.org> * + * * + * Based on Logitech G13 driver (v0.4) * + * Copyright (C) 2009 by Rick L. Vinyard, Jr. <rvinyard@cs.nmsu.edu> * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, version 2 of the License. * + * * + * This driver is distributed in the hope that it will be useful, but * + * WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * + * General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this software. If not see <http://www.gnu.org/licenses/>. * + ***************************************************************************/ + +#include <linux/hid.h> +#include <linux/hid-debug.h> +#include <linux/input.h> +#include "hid-ids.h" +#include "usbhid/usbhid.h" +#include <linux/usb.h> + +#include <linux/fb.h> +#include <linux/vmalloc.h> +#include <linux/backlight.h> +#include <linux/lcd.h> + +#include <linux/leds.h> + +#include <linux/seq_file.h> +#include <linux/debugfs.h> + +#include <linux/completion.h> +#include <linux/uaccess.h> + +#define PICOLCD_NAME "PicoLCD (graphic)" + +/* Report numbers */ +#define REPORT_ERROR_CODE 0x10 /* LCD: IN[16] */ +#define ERR_SUCCESS 0x00 +#define ERR_PARAMETER_MISSING 0x01 +#define ERR_DATA_MISSING 0x02 +#define ERR_BLOCK_READ_ONLY 0x03 +#define ERR_BLOCK_NOT_ERASABLE 0x04 +#define ERR_BLOCK_TOO_BIG 0x05 +#define ERR_SECTION_OVERFLOW 0x06 +#define ERR_INVALID_CMD_LEN 0x07 +#define ERR_INVALID_DATA_LEN 0x08 +#define REPORT_KEY_STATE 0x11 /* LCD: IN[2] */ +#define REPORT_IR_DATA 0x21 /* LCD: IN[63] */ +#define REPORT_EE_DATA 0x32 /* LCD: IN[63] */ +#define REPORT_MEMORY 0x41 /* LCD: IN[63] */ +#define REPORT_LED_STATE 0x81 /* LCD: OUT[1] */ +#define REPORT_BRIGHTNESS 0x91 /* LCD: OUT[1] */ +#define REPORT_CONTRAST 0x92 /* LCD: OUT[1] */ +#define REPORT_RESET 0x93 /* LCD: OUT[2] */ +#define REPORT_LCD_CMD 0x94 /* LCD: OUT[63] */ +#define REPORT_LCD_DATA 0x95 /* LCD: OUT[63] */ +#define REPORT_LCD_CMD_DATA 0x96 /* LCD: OUT[63] */ +#define REPORT_EE_READ 0xa3 /* LCD: OUT[63] */ +#define REPORT_EE_WRITE 0xa4 /* LCD: OUT[63] */ +#define REPORT_ERASE_MEMORY 0xb2 /* LCD: OUT[2] */ +#define REPORT_READ_MEMORY 0xb3 /* LCD: OUT[3] */ +#define REPORT_WRITE_MEMORY 0xb4 /* LCD: OUT[63] */ +#define REPORT_SPLASH_RESTART 0xc1 /* LCD: OUT[1] */ +#define REPORT_EXIT_KEYBOARD 0xef /* LCD: OUT[2] */ +#define REPORT_VERSION 0xf1 /* LCD: IN[2],OUT[1] Bootloader: IN[2],OUT[1] */ +#define REPORT_BL_ERASE_MEMORY 0xf2 /* Bootloader: IN[36],OUT[4] */ +#define REPORT_BL_READ_MEMORY 0xf3 /* Bootloader: IN[36],OUT[4] */ +#define REPORT_BL_WRITE_MEMORY 0xf4 /* Bootloader: IN[36],OUT[36] */ +#define REPORT_DEVID 0xf5 /* LCD: IN[5], OUT[1] Bootloader: IN[5],OUT[1] */ +#define REPORT_SPLASH_SIZE 0xf6 /* LCD: IN[4], OUT[1] */ +#define REPORT_HOOK_VERSION 0xf7 /* LCD: IN[2], OUT[1] */ +#define REPORT_EXIT_FLASHER 0xff /* Bootloader: OUT[2] */ + +#ifdef CONFIG_HID_PICOLCD_FB +/* Framebuffer + * + * The PicoLCD use a Topway LCD module of 256x64 pixel + * This display area is tiled over 4 controllers with 8 tiles + * each. Each tile has 8x64 pixel, each data byte representing + * a 1-bit wide vertical line of the tile. + * + * The display can be updated at a tile granularity. + * + * Chip 1 Chip 2 Chip 3 Chip 4 + * +----------------+----------------+----------------+----------------+ + * | Tile 1 | Tile 1 | Tile 1 | Tile 1 | + * +----------------+----------------+----------------+----------------+ + * | Tile 2 | Tile 2 | Tile 2 | Tile 2 | + * +----------------+----------------+----------------+----------------+ + * ... + * +----------------+----------------+----------------+----------------+ + * | Tile 8 | Tile 8 | Tile 8 | Tile 8 | + * +----------------+----------------+----------------+----------------+ + */ +#define PICOLCDFB_NAME "picolcdfb" +#define PICOLCDFB_WIDTH (256) +#define PICOLCDFB_HEIGHT (64) +#define PICOLCDFB_SIZE (PICOLCDFB_WIDTH * PICOLCDFB_HEIGHT / 8) + +#define PICOLCDFB_UPDATE_RATE_LIMIT 10 +#define PICOLCDFB_UPDATE_RATE_DEFAULT 2 + +/* Framebuffer visual structures */ +static const struct fb_fix_screeninfo picolcdfb_fix = { + .id = PICOLCDFB_NAME, + .type = FB_TYPE_PACKED_PIXELS, + .visual = FB_VISUAL_MONO01, + .xpanstep = 0, + .ypanstep = 0, + .ywrapstep = 0, + .line_length = PICOLCDFB_WIDTH / 8, + .accel = FB_ACCEL_NONE, +}; + +static const struct fb_var_screeninfo picolcdfb_var = { + .xres = PICOLCDFB_WIDTH, + .yres = PICOLCDFB_HEIGHT, + .xres_virtual = PICOLCDFB_WIDTH, + .yres_virtual = PICOLCDFB_HEIGHT, + .width = 103, + .height = 26, + .bits_per_pixel = 1, + .grayscale = 1, +}; +#endif /* CONFIG_HID_PICOLCD_FB */ + +/* Input device + * + * The PicoLCD has an IR receiver header, a built-in keypad with 5 keys + * and header for 4x4 key matrix. The built-in keys are part of the matrix. + */ +static const unsigned short def_keymap[] = { + KEY_RESERVED, /* none */ + KEY_BACK, /* col 4 + row 1 */ + KEY_HOMEPAGE, /* col 3 + row 1 */ + KEY_RESERVED, /* col 2 + row 1 */ + KEY_RESERVED, /* col 1 + row 1 */ + KEY_SCROLLUP, /* col 4 + row 2 */ + KEY_OK, /* col 3 + row 2 */ + KEY_SCROLLDOWN, /* col 2 + row 2 */ + KEY_RESERVED, /* col 1 + row 2 */ + KEY_RESERVED, /* col 4 + row 3 */ + KEY_RESERVED, /* col 3 + row 3 */ + KEY_RESERVED, /* col 2 + row 3 */ + KEY_RESERVED, /* col 1 + row 3 */ + KEY_RESERVED, /* col 4 + row 4 */ + KEY_RESERVED, /* col 3 + row 4 */ + KEY_RESERVED, /* col 2 + row 4 */ + KEY_RESERVED, /* col 1 + row 4 */ +}; +#define PICOLCD_KEYS ARRAY_SIZE(def_keymap) + +/* Description of in-progress IO operation, used for operations + * that trigger response from device */ +struct picolcd_pending { + struct hid_report *out_report; + struct hid_report *in_report; + struct completion ready; + int raw_size; + u8 raw_data[64]; +}; + +/* Per device data structure */ +struct picolcd_data { + struct hid_device *hdev; +#ifdef CONFIG_DEBUG_FS + struct dentry *debug_reset; + struct dentry *debug_eeprom; + struct dentry *debug_flash; + struct mutex mutex_flash; + int addr_sz; +#endif + u8 version[2]; + unsig |