Commit 5884c406 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'upstream-fixes' of master.kernel.org:/pub/scm/linux/kernel/git/jikos/hid

* 'upstream-fixes' of master.kernel.org:/pub/scm/linux/kernel/git/jikos/hid:
  USB HID: hiddev - fix race between hiddev_send_event() and hiddev_release()
  HID: add hooks for getkeycode() and setkeycode() methods
  HID: switch to using input_dev->dev.parent
  USB HID: Logitech wheel 0x046d/0xc294 needs HID_QUIRK_NOGET quirk
  USB HID: usb_buffer_free() cleanup
  USB HID: report descriptor of Cypress USB barcode readers needs fixup
  Bluetooth HID: HIDP - don't initialize force feedback
  USB HID: update CONFIG_USB_HIDINPUT_POWERBOOK description
  HID: add input mappings for non-working keys on Logitech S510 remote
parents ee54d2d8 cdcb44e8
......@@ -240,11 +240,94 @@ static inline void hidinput_pb_setup(struct input_dev *input)
}
#endif
static inline int match_scancode(int code, int scancode)
{
if (scancode == 0)
return 1;
return ((code & (HID_USAGE_PAGE | HID_USAGE)) == scancode);
}
static inline int match_keycode(int code, int keycode)
{
if (keycode == 0)
return 1;
return (code == keycode);
}
static struct hid_usage *hidinput_find_key(struct hid_device *hid,
int scancode, int keycode)
{
int i, j, k;
struct hid_report *report;
struct hid_usage *usage;
for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++) {
list_for_each_entry(report, &hid->report_enum[k].report_list, list) {
for (i = 0; i < report->maxfield; i++) {
for ( j = 0; j < report->field[i]->maxusage; j++) {
usage = report->field[i]->usage + j;
if (usage->type == EV_KEY &&
match_scancode(usage->hid, scancode) &&
match_keycode(usage->code, keycode))
return usage;
}
}
}
}
return NULL;
}
static int hidinput_getkeycode(struct input_dev *dev, int scancode,
int *keycode)
{
struct hid_device *hid = dev->private;
struct hid_usage *usage;
usage = hidinput_find_key(hid, scancode, 0);
if (usage) {
*keycode = usage->code;
return 0;
}
return -EINVAL;
}
static int hidinput_setkeycode(struct input_dev *dev, int scancode,
int keycode)
{
struct hid_device *hid = dev->private;
struct hid_usage *usage;
int old_keycode;
if (keycode < 0 || keycode > KEY_MAX)
return -EINVAL;
usage = hidinput_find_key(hid, scancode, 0);
if (usage) {
old_keycode = usage->code;
usage->code = keycode;
clear_bit(old_keycode, dev->keybit);
set_bit(usage->code, dev->keybit);
#ifdef CONFIG_HID_DEBUG
printk (KERN_DEBUG "Assigned keycode %d to HID usage code %x\n", keycode, scancode);
#endif
/* Set the keybit for the old keycode if the old keycode is used
* by another key */
if (hidinput_find_key (hid, 0, old_keycode))
set_bit(old_keycode, dev->keybit);
return 0;
}
return -EINVAL;
}
static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_field *field,
struct hid_usage *usage)
{
struct input_dev *input = hidinput->input;
struct hid_device *device = input->private;
struct hid_device *device = input_get_drvdata(input);
int max = 0, code;
unsigned long *bit = NULL;
......@@ -553,6 +636,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case 0x1015: map_key_clear(KEY_RECORD); break;
case 0x1016: map_key_clear(KEY_PLAYER); break;
case 0x1017: map_key_clear(KEY_EJECTCD); break;
case 0x1018: map_key_clear(KEY_MEDIA); break;
case 0x1019: map_key_clear(KEY_PROG1); break;
case 0x101a: map_key_clear(KEY_PROG2); break;
case 0x101b: map_key_clear(KEY_PROG3); break;
......@@ -560,9 +644,12 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
case 0x1020: map_key_clear(KEY_ZOOMOUT); break;
case 0x1021: map_key_clear(KEY_ZOOMRESET); break;
case 0x1023: map_key_clear(KEY_CLOSE); break;
case 0x1027: map_key_clear(KEY_MENU); break;
/* this one is marked as 'Rotate' */
case 0x1028: map_key_clear(KEY_ANGLE); break;
case 0x1029: map_key_clear(KEY_SHUFFLE); break;
case 0x102a: map_key_clear(KEY_BACK); break;
case 0x102b: map_key_clear(KEY_CYCLEWINDOWS); break;
case 0x1041: map_key_clear(KEY_BATTERY); break;
case 0x1042: map_key_clear(KEY_WORDPROCESSOR); break;
case 0x1043: map_key_clear(KEY_SPREADSHEET); break;
......@@ -855,13 +942,15 @@ EXPORT_SYMBOL_GPL(hidinput_find_field);
static int hidinput_open(struct input_dev *dev)
{
struct hid_device *hid = dev->private;
struct hid_device *hid = input_get_drvdata(dev);
return hid->hid_open(hid);
}
static void hidinput_close(struct input_dev *dev)
{
struct hid_device *hid = dev->private;
struct hid_device *hid = input_get_drvdata(dev);
hid->hid_close(hid);
}
......@@ -909,10 +998,12 @@ int hidinput_connect(struct hid_device *hid)
return -1;
}
input_dev->private = hid;
input_set_drvdata(input_dev, hid);
input_dev->event = hid->hidinput_input_event;
input_dev->open = hidinput_open;
input_dev->close = hidinput_close;
input_dev->setkeycode = hidinput_setkeycode;
input_dev->getkeycode = hidinput_getkeycode;
input_dev->name = hid->name;
input_dev->phys = hid->phys;
......@@ -921,7 +1012,7 @@ int hidinput_connect(struct hid_device *hid)
input_dev->id.vendor = hid->vendor;
input_dev->id.product = hid->product;
input_dev->id.version = hid->version;
input_dev->cdev.dev = hid->dev;
input_dev->dev.parent = hid->dev;
hidinput->input = input_dev;
list_add_tail(&hidinput->list, &hid->inputs);
}
......
......@@ -25,12 +25,12 @@ comment "Input core support is needed for USB HID input layer or HIDBP support"
depends on USB_HID && INPUT=n
config USB_HIDINPUT_POWERBOOK
bool "Enable support for iBook/PowerBook special keys"
bool "Enable support for iBook/PowerBook/MacBook/MacBookPro special keys"
default n
depends on USB_HID
help
Say Y here if you want support for the special keys (Fn, Numlock) on
Apple iBooks and PowerBooks.
Apple iBooks, PowerBooks, MacBooks and MacBook Pros.
If unsure, say N.
......
......@@ -446,7 +446,7 @@ void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, uns
static int usb_hidinput_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
{
struct hid_device *hid = dev->private;
struct hid_device *hid = input_get_drvdata(dev);
struct hid_field *field;
int offset;
......@@ -626,13 +626,9 @@ static void hid_free_buffers(struct usb_device *dev, struct hid_device *hid)
{
struct usbhid_device *usbhid = hid->driver_data;
if (usbhid->inbuf)
usb_buffer_free(dev, usbhid->bufsize, usbhid->inbuf, usbhid->inbuf_dma);
if (usbhid->outbuf)
usb_buffer_free(dev, usbhid->bufsize, usbhid->outbuf, usbhid->outbuf_dma);
if (usbhid->cr)
usb_buffer_free(dev, sizeof(*(usbhid->cr)), usbhid->cr, usbhid->cr_dma);
if (usbhid->ctrlbuf)
usb_buffer_free(dev, usbhid->bufsize, usbhid->ctrlbuf, usbhid->ctrlbuf_dma);
}
......@@ -692,6 +688,30 @@ static void hid_fixup_logitech_descriptor(unsigned char *rdesc, int rsize)
}
}
/*
* Some USB barcode readers from cypress have usage min and usage max in
* the wrong order
*/
static void hid_fixup_cypress_descriptor(unsigned char *rdesc, int rsize)
{
short fixed = 0;
int i;
for (i = 0; i < rsize - 4; i++) {
if (rdesc[i] == 0x29 && rdesc [i+2] == 0x19) {
unsigned char tmp;
rdesc[i] = 0x19; rdesc[i+2] = 0x29;
tmp = rdesc[i+3];
rdesc[i+3] = rdesc[i+1];
rdesc[i+1] = tmp;
}
}
if (fixed)
info("Fixing up Cypress report descriptor");
}
static struct hid_device *usb_hid_configure(struct usb_interface *intf)
{
struct usb_host_interface *interface = intf->cur_altsetting;
......@@ -758,6 +778,9 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
if (quirks & HID_QUIRK_LOGITECH_DESCRIPTOR)
hid_fixup_logitech_descriptor(rdesc, rsize);
if (quirks & HID_QUIRK_SWAPPED_MIN_MAX)
hid_fixup_cypress_descriptor(rdesc, rsize);
#ifdef CONFIG_HID_DEBUG
printk(KERN_DEBUG __FILE__ ": report descriptor (size %u, read %d) = ", rsize, n);
for (n = 0; n < rsize; n++)
......
......@@ -60,7 +60,7 @@ static const struct dev_type devices[] = {
static int hid_lgff_play(struct input_dev *dev, void *data, struct ff_effect *effect)
{
struct hid_device *hid = dev->private;
struct hid_device *hid = input_get_drvdata(dev);
struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list;
struct hid_report *report = list_entry(report_list->next, struct hid_report, list);
int x, y;
......
......@@ -37,7 +37,7 @@ struct plff_device {
static int hid_plff_play(struct input_dev *dev, void *data,
struct ff_effect *effect)
{
struct hid_device *hid = dev->private;
struct hid_device *hid = input_get_drvdata(dev);
struct plff_device *plff = data;
int left, right;
......
......@@ -92,6 +92,8 @@
#define USB_DEVICE_ID_CYPRESS_MOUSE 0x0001
#define USB_DEVICE_ID_CYPRESS_HIDCOM 0x5500
#define USB_DEVICE_ID_CYPRESS_ULTRAMOUSE 0x7417
#define USB_DEVICE_ID_CYPRESS_BARCODE_1 0xde61
#define USB_DEVICE_ID_CYPRESS_BARCODE_2 0xde64
#define USB_VENDOR_ID_DELL 0x413c
#define USB_DEVICE_ID_DELL_W7658 0x2005
......@@ -193,6 +195,7 @@
#define USB_VENDOR_ID_LOGITECH 0x046d
#define USB_DEVICE_ID_LOGITECH_RECEIVER 0xc101
#define USB_DEVICE_ID_LOGITECH_WHEEL 0xc294
#define USB_DEVICE_ID_S510_RECEIVER 0xc50c
#define USB_DEVICE_ID_S510_RECEIVER_2 0xc517
#define USB_DEVICE_ID_MX3000_RECEIVER 0xc513
......@@ -422,6 +425,7 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVM, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVMC, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WHEEL, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT },
......@@ -445,6 +449,9 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_DELL, USB_DEVICE_ID_DELL_W7658, HID_QUIRK_RESET_LEDS },
{ USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1, HID_QUIRK_SWAPPED_MIN_MAX },
{ USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2, HID_QUIRK_SWAPPED_MIN_MAX },
{ 0, 0 }
};
......
......@@ -59,7 +59,7 @@ static inline int hid_tmff_scale(unsigned int in, int minimum, int maximum)
static int hid_tmff_play(struct input_dev *dev, void *data, struct ff_effect *effect)
{
struct hid_device *hid = dev->private;
struct hid_device *hid = input_get_drvdata(dev);
struct tmff_device *tmff = data;
int left, right; /* Rumbling */
......
......@@ -37,7 +37,7 @@ struct zpff_device {
static int hid_zpff_play(struct input_dev *dev, void *data,
struct ff_effect *effect)
{
struct hid_device *hid = dev->private;
struct hid_device *hid = input_get_drvdata(dev);
struct zpff_device *zpff = data;
int left, right;
......
......@@ -51,6 +51,7 @@ struct hiddev {
wait_queue_head_t wait;
struct hid_device *hid;
struct list_head list;
spinlock_t list_lock;
};
struct hiddev_list {
......@@ -161,7 +162,9 @@ static void hiddev_send_event(struct hid_device *hid,
{
struct hiddev *hiddev = hid->hiddev;
struct hiddev_list *list;
unsigned long flags;
spin_lock_irqsave(&hiddev->list_lock, flags);
list_for_each_entry(list, &hiddev->list, node) {
if (uref->field_index != HID_FIELD_INDEX_NONE ||
(list->flags & HIDDEV_FLAG_REPORT) != 0) {
......@@ -171,6 +174,7 @@ static void hiddev_send_event(struct hid_device *hid,
kill_fasync(&list->fasync, SIGIO, POLL_IN);
}
}
spin_unlock_irqrestore(&hiddev->list_lock, flags);
wake_up_interruptible(&hiddev->wait);
}
......@@ -235,9 +239,13 @@ static int hiddev_fasync(int fd, struct file *file, int on)
static int hiddev_release(struct inode * inode, struct file * file)
{
struct hiddev_list *list = file->private_data;
unsigned long flags;
hiddev_fasync(-1, file, 0);
spin_lock_irqsave(&list->hiddev->list_lock, flags);
list_del(&list->node);
spin_unlock_irqrestore(&list->hiddev->list_lock, flags);
if (!--list->hiddev->open) {
if (list->hiddev->exist)
......@@ -257,6 +265,7 @@ static int hiddev_release(struct inode * inode, struct file * file)
static int hiddev_open(struct inode *inode, struct file *file)
{
struct hiddev_list *list;
unsigned long flags;
int i = iminor(inode) - HIDDEV_MINOR_BASE;
......@@ -267,7 +276,11 @@ static int hiddev_open(struct inode *inode, struct file *file)
return -ENOMEM;
list->hiddev = hiddev_table[i];
spin_lock_irqsave(&list->hiddev->list_lock, flags);
list_add_tail(&list->node, &hiddev_table[i]->list);
spin_unlock_irqrestore(&list->hiddev->list_lock, flags);
file->private_data = list;
if (!list->hiddev->open++)
......@@ -773,6 +786,7 @@ int hiddev_connect(struct hid_device *hid)
init_waitqueue_head(&hiddev->wait);
INIT_LIST_HEAD(&hiddev->list);
spin_lock_init(&hiddev->list_lock);
hiddev->hid = hid;
hiddev->exist = 1;
......
......@@ -133,12 +133,11 @@ resubmit:
static int usb_kbd_event(struct input_dev *dev, unsigned int type,
unsigned int code, int value)
{
struct usb_kbd *kbd = dev->private;
struct usb_kbd *kbd = input_get_drvdata(dev);
if (type != EV_LED)
return -1;
kbd->newleds = (!!test_bit(LED_KANA, dev->led) << 3) | (!!test_bit(LED_COMPOSE, dev->led) << 3) |
(!!test_bit(LED_SCROLLL, dev->led) << 2) | (!!test_bit(LED_CAPSL, dev->led) << 1) |
(!!test_bit(LED_NUML, dev->led));
......@@ -175,7 +174,7 @@ static void usb_kbd_led(struct urb *urb)
static int usb_kbd_open(struct input_dev *dev)
{
struct usb_kbd *kbd = dev->private;
struct usb_kbd *kbd = input_get_drvdata(dev);
kbd->irq->dev = kbd->usbdev;
if (usb_submit_urb(kbd->irq, GFP_KERNEL))
......@@ -186,7 +185,7 @@ static int usb_kbd_open(struct input_dev *dev)
static void usb_kbd_close(struct input_dev *dev)
{
struct usb_kbd *kbd = dev->private;
struct usb_kbd *kbd = input_get_drvdata(dev);
usb_kill_urb(kbd->irq);
}
......@@ -211,11 +210,8 @@ static void usb_kbd_free_mem(struct usb_device *dev, struct usb_kbd *kbd)
{
usb_free_urb(kbd->irq);
usb_free_urb(kbd->led);
if (kbd->new)
usb_buffer_free(dev, 8, kbd->new, kbd->new_dma);
if (kbd->cr)
usb_buffer_free(dev, sizeof(struct usb_ctrlrequest), kbd->cr, kbd->cr_dma);
if (kbd->leds)
usb_buffer_free(dev, 1, kbd->leds, kbd->leds_dma);
}
......@@ -274,8 +270,9 @@ static int usb_kbd_probe(struct usb_interface *iface,
input_dev->name = kbd->name;
input_dev->phys = kbd->phys;
usb_to_input_id(dev, &input_dev->id);
input_dev->cdev.dev = &iface->dev;
input_dev->private = kbd;
input_dev->dev.parent = &iface->dev;
input_set_drvdata(input_dev, kbd);
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_LED) | BIT(EV_REP);
input_dev->ledbit[0] = BIT(LED_NUML) | BIT(LED_CAPSL) | BIT(LED_SCROLLL) | BIT(LED_COMPOSE) | BIT(LED_KANA);
......
......@@ -96,7 +96,7 @@ resubmit:
static int usb_mouse_open(struct input_dev *dev)
{
struct usb_mouse *mouse = dev->private;
struct usb_mouse *mouse = input_get_drvdata(dev);
mouse->irq->dev = mouse->usbdev;
if (usb_submit_urb(mouse->irq, GFP_KERNEL))
......@@ -107,7 +107,7 @@ static int usb_mouse_open(struct input_dev *dev)
static void usb_mouse_close(struct input_dev *dev)
{
struct usb_mouse *mouse = dev->private;
struct usb_mouse *mouse = input_get_drvdata(dev);
usb_kill_urb(mouse->irq);
}
......@@ -171,7 +171,7 @@ static int usb_mouse_probe(struct usb_interface *intf, const struct usb_device_i
input_dev->name = mouse->name;
input_dev->phys = mouse->phys;
usb_to_input_id(dev, &input_dev->id);
input_dev->cdev.dev = &intf->dev;
input_dev->dev.parent = &intf->dev;
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL);
input_dev->keybit[LONG(BTN_MOUSE)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT) | BIT(BTN_MIDDLE);
......@@ -179,7 +179,8 @@ static int usb_mouse_probe(struct usb_interface *intf, const struct usb_device_i
input_dev->keybit[LONG(BTN_MOUSE)] |= BIT(BTN_SIDE) | BIT(BTN_EXTRA);
input_dev->relbit[0] |= BIT(REL_WHEEL);
input_dev->private = mouse;
input_set_drvdata(input_dev, mouse);
input_dev->open = usb_mouse_open;
input_dev->close = usb_mouse_close;
......
......@@ -275,6 +275,7 @@ struct hid_item {
#define HID_QUIRK_LOGITECH_DESCRIPTOR 0x00100000
#define HID_QUIRK_DUPLICATE_USAGES 0x00200000
#define HID_QUIRK_RESET_LEDS 0x00400000
#define HID_QUIRK_SWAPPED_MIN_MAX 0x00800000
/*
* This is the global environment of the parser. This information is
......
......@@ -737,10 +737,8 @@ static inline void hidp_setup_hid(struct hidp_session *session, struct hidp_conn
list_for_each_entry(report, &hid->report_enum[HID_FEATURE_REPORT].report_list, list)
hidp_send_report(session, report);
if (hidinput_connect(hid) == 0) {
if (hidinput_connect(hid) == 0)
hid->claimed |= HID_CLAIMED_INPUT;
hid_ff_init(hid);
}
}
int hidp_add_connection(struct hidp_connadd_req *req, struct socket *ctrl_sock, struct socket *intr_sock)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment