Skip to content

Commit

Permalink
Merge branch 'upstream-fixes' of master.kernel.org:/pub/scm/linux/ker…
Browse files Browse the repository at this point in the history
…nel/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
  • Loading branch information
Linus Torvalds committed May 11, 2007
2 parents ee54d2d + cdcb44e commit 5884c40
Show file tree
Hide file tree
Showing 13 changed files with 171 additions and 39 deletions.
101 changes: 96 additions & 5 deletions drivers/hid/hid-input.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -553,16 +636,20 @@ 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;
case 0x101f: map_key_clear(KEY_ZOOMIN); break;
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;
Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -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;
Expand All @@ -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);
}
Expand Down
4 changes: 2 additions & 2 deletions drivers/hid/usbhid/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down
41 changes: 32 additions & 9 deletions drivers/hid/usbhid/hid-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -626,14 +626,10 @@ 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);
usb_buffer_free(dev, usbhid->bufsize, usbhid->inbuf, usbhid->inbuf_dma);
usb_buffer_free(dev, usbhid->bufsize, usbhid->outbuf, usbhid->outbuf_dma);
usb_buffer_free(dev, sizeof(*(usbhid->cr)), usbhid->cr, usbhid->cr_dma);
usb_buffer_free(dev, usbhid->bufsize, usbhid->ctrlbuf, usbhid->ctrlbuf_dma);
}

/*
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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++)
Expand Down
2 changes: 1 addition & 1 deletion drivers/hid/usbhid/hid-lgff.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion drivers/hid/usbhid/hid-plff.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
7 changes: 7 additions & 0 deletions drivers/hid/usbhid/hid-quirks.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 },
Expand All @@ -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 }
};

Expand Down
2 changes: 1 addition & 1 deletion drivers/hid/usbhid/hid-tmff.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 */

Expand Down
2 changes: 1 addition & 1 deletion drivers/hid/usbhid/hid-zpff.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
14 changes: 14 additions & 0 deletions drivers/hid/usbhid/hiddev.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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) {
Expand All @@ -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);
}
Expand Down Expand Up @@ -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)
Expand All @@ -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;

Expand All @@ -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++)
Expand Down Expand Up @@ -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;

Expand Down
Loading

0 comments on commit 5884c40

Please sign in to comment.