diff options
| author | John W. Linville <linville@tuxdriver.com> | 2006-08-14 15:33:54 -0400 |
|---|---|---|
| committer | John W. Linville <linville@tuxdriver.com> | 2006-08-14 15:33:54 -0400 |
| commit | e9ffb3d7ec94083a44a8721681391beca2ffd68c (patch) | |
| tree | 6768ab487b3f44c2a4995ee61307e47760ca9b88 /drivers/usb/input/hiddev.c | |
| parent | 8b9411014e6f18a883c18b38f41338dbd53fddea (diff) | |
| parent | e9fa4f7bd291c29a785666e2fa5a9cf3241ee6c3 (diff) | |
Merge branch 'from-linus' into upstream
Diffstat (limited to 'drivers/usb/input/hiddev.c')
| -rw-r--r-- | drivers/usb/input/hiddev.c | 72 |
1 files changed, 38 insertions, 34 deletions
diff --git a/drivers/usb/input/hiddev.c b/drivers/usb/input/hiddev.c index 70477f02cc29..f6b839c257a7 100644 --- a/drivers/usb/input/hiddev.c +++ b/drivers/usb/input/hiddev.c | |||
| @@ -49,7 +49,7 @@ struct hiddev { | |||
| 49 | int open; | 49 | int open; |
| 50 | wait_queue_head_t wait; | 50 | wait_queue_head_t wait; |
| 51 | struct hid_device *hid; | 51 | struct hid_device *hid; |
| 52 | struct hiddev_list *list; | 52 | struct list_head list; |
| 53 | }; | 53 | }; |
| 54 | 54 | ||
| 55 | struct hiddev_list { | 55 | struct hiddev_list { |
| @@ -59,7 +59,7 @@ struct hiddev_list { | |||
| 59 | unsigned flags; | 59 | unsigned flags; |
| 60 | struct fasync_struct *fasync; | 60 | struct fasync_struct *fasync; |
| 61 | struct hiddev *hiddev; | 61 | struct hiddev *hiddev; |
| 62 | struct hiddev_list *next; | 62 | struct list_head node; |
| 63 | }; | 63 | }; |
| 64 | 64 | ||
| 65 | static struct hiddev *hiddev_table[HIDDEV_MINORS]; | 65 | static struct hiddev *hiddev_table[HIDDEV_MINORS]; |
| @@ -73,12 +73,15 @@ static struct hiddev *hiddev_table[HIDDEV_MINORS]; | |||
| 73 | static struct hid_report * | 73 | static struct hid_report * |
| 74 | hiddev_lookup_report(struct hid_device *hid, struct hiddev_report_info *rinfo) | 74 | hiddev_lookup_report(struct hid_device *hid, struct hiddev_report_info *rinfo) |
| 75 | { | 75 | { |
| 76 | unsigned flags = rinfo->report_id & ~HID_REPORT_ID_MASK; | 76 | unsigned int flags = rinfo->report_id & ~HID_REPORT_ID_MASK; |
| 77 | unsigned int rid = rinfo->report_id & HID_REPORT_ID_MASK; | ||
| 77 | struct hid_report_enum *report_enum; | 78 | struct hid_report_enum *report_enum; |
| 79 | struct hid_report *report; | ||
| 78 | struct list_head *list; | 80 | struct list_head *list; |
| 79 | 81 | ||
| 80 | if (rinfo->report_type < HID_REPORT_TYPE_MIN || | 82 | if (rinfo->report_type < HID_REPORT_TYPE_MIN || |
| 81 | rinfo->report_type > HID_REPORT_TYPE_MAX) return NULL; | 83 | rinfo->report_type > HID_REPORT_TYPE_MAX) |
| 84 | return NULL; | ||
| 82 | 85 | ||
| 83 | report_enum = hid->report_enum + | 86 | report_enum = hid->report_enum + |
| 84 | (rinfo->report_type - HID_REPORT_TYPE_MIN); | 87 | (rinfo->report_type - HID_REPORT_TYPE_MIN); |
| @@ -88,21 +91,25 @@ hiddev_lookup_report(struct hid_device *hid, struct hiddev_report_info *rinfo) | |||
| 88 | break; | 91 | break; |
| 89 | 92 | ||
| 90 | case HID_REPORT_ID_FIRST: | 93 | case HID_REPORT_ID_FIRST: |
| 91 | list = report_enum->report_list.next; | 94 | if (list_empty(&report_enum->report_list)) |
| 92 | if (list == &report_enum->report_list) | ||
| 93 | return NULL; | 95 | return NULL; |
| 94 | rinfo->report_id = ((struct hid_report *) list)->id; | 96 | |
| 97 | list = report_enum->report_list.next; | ||
| 98 | report = list_entry(list, struct hid_report, list); | ||
| 99 | rinfo->report_id = report->id; | ||
| 95 | break; | 100 | break; |
| 96 | 101 | ||
| 97 | case HID_REPORT_ID_NEXT: | 102 | case HID_REPORT_ID_NEXT: |
| 98 | list = (struct list_head *) | 103 | report = report_enum->report_id_hash[rid]; |
| 99 | report_enum->report_id_hash[rinfo->report_id & HID_REPORT_ID_MASK]; | 104 | if (!report) |
| 100 | if (list == NULL) | ||
| 101 | return NULL; | 105 | return NULL; |
| 102 | list = list->next; | 106 | |
| 107 | list = report->list.next; | ||
| 103 | if (list == &report_enum->report_list) | 108 | if (list == &report_enum->report_list) |
| 104 | return NULL; | 109 | return NULL; |
| 105 | rinfo->report_id = ((struct hid_report *) list)->id; | 110 | |
| 111 | report = list_entry(list, struct hid_report, list); | ||
| 112 | rinfo->report_id = report->id; | ||
| 106 | break; | 113 | break; |
| 107 | 114 | ||
| 108 | default: | 115 | default: |
| @@ -125,12 +132,13 @@ hiddev_lookup_usage(struct hid_device *hid, struct hiddev_usage_ref *uref) | |||
| 125 | struct hid_field *field; | 132 | struct hid_field *field; |
| 126 | 133 | ||
| 127 | if (uref->report_type < HID_REPORT_TYPE_MIN || | 134 | if (uref->report_type < HID_REPORT_TYPE_MIN || |
| 128 | uref->report_type > HID_REPORT_TYPE_MAX) return NULL; | 135 | uref->report_type > HID_REPORT_TYPE_MAX) |
| 136 | return NULL; | ||
| 129 | 137 | ||
| 130 | report_enum = hid->report_enum + | 138 | report_enum = hid->report_enum + |
| 131 | (uref->report_type - HID_REPORT_TYPE_MIN); | 139 | (uref->report_type - HID_REPORT_TYPE_MIN); |
| 132 | 140 | ||
| 133 | list_for_each_entry(report, &report_enum->report_list, list) | 141 | list_for_each_entry(report, &report_enum->report_list, list) { |
| 134 | for (i = 0; i < report->maxfield; i++) { | 142 | for (i = 0; i < report->maxfield; i++) { |
| 135 | field = report->field[i]; | 143 | field = report->field[i]; |
| 136 | for (j = 0; j < field->maxusage; j++) { | 144 | for (j = 0; j < field->maxusage; j++) { |
| @@ -142,6 +150,7 @@ hiddev_lookup_usage(struct hid_device *hid, struct hiddev_usage_ref *uref) | |||
| 142 | } | 150 | } |
| 143 | } | 151 | } |
| 144 | } | 152 | } |
| 153 | } | ||
| 145 | 154 | ||
| 146 | return NULL; | 155 | return NULL; |
| 147 | } | 156 | } |
| @@ -150,9 +159,9 @@ static void hiddev_send_event(struct hid_device *hid, | |||
| 150 | struct hiddev_usage_ref *uref) | 159 | struct hiddev_usage_ref *uref) |
| 151 | { | 160 | { |
| 152 | struct hiddev *hiddev = hid->hiddev; | 161 | struct hiddev *hiddev = hid->hiddev; |
| 153 | struct hiddev_list *list = hiddev->list; | 162 | struct hiddev_list *list; |
| 154 | 163 | ||
| 155 | while (list) { | 164 | list_for_each_entry(list, &hiddev->list, node) { |
| 156 | if (uref->field_index != HID_FIELD_INDEX_NONE || | 165 | if (uref->field_index != HID_FIELD_INDEX_NONE || |
| 157 | (list->flags & HIDDEV_FLAG_REPORT) != 0) { | 166 | (list->flags & HIDDEV_FLAG_REPORT) != 0) { |
| 158 | list->buffer[list->head] = *uref; | 167 | list->buffer[list->head] = *uref; |
| @@ -160,8 +169,6 @@ static void hiddev_send_event(struct hid_device *hid, | |||
| 160 | (HIDDEV_BUFFER_SIZE - 1); | 169 | (HIDDEV_BUFFER_SIZE - 1); |
| 161 | kill_fasync(&list->fasync, SIGIO, POLL_IN); | 170 | kill_fasync(&list->fasync, SIGIO, POLL_IN); |
| 162 | } | 171 | } |
| 163 | |||
| 164 | list = list->next; | ||
| 165 | } | 172 | } |
| 166 | 173 | ||
| 167 | wake_up_interruptible(&hiddev->wait); | 174 | wake_up_interruptible(&hiddev->wait); |
| @@ -180,7 +187,7 @@ void hiddev_hid_event(struct hid_device *hid, struct hid_field *field, | |||
| 180 | uref.report_type = | 187 | uref.report_type = |
| 181 | (type == HID_INPUT_REPORT) ? HID_REPORT_TYPE_INPUT : | 188 | (type == HID_INPUT_REPORT) ? HID_REPORT_TYPE_INPUT : |
| 182 | ((type == HID_OUTPUT_REPORT) ? HID_REPORT_TYPE_OUTPUT : | 189 | ((type == HID_OUTPUT_REPORT) ? HID_REPORT_TYPE_OUTPUT : |
| 183 | ((type == HID_FEATURE_REPORT) ? HID_REPORT_TYPE_FEATURE:0)); | 190 | ((type == HID_FEATURE_REPORT) ? HID_REPORT_TYPE_FEATURE : 0)); |
| 184 | uref.report_id = field->report->id; | 191 | uref.report_id = field->report->id; |
| 185 | uref.field_index = field->index; | 192 | uref.field_index = field->index; |
| 186 | uref.usage_index = (usage - field->usage); | 193 | uref.usage_index = (usage - field->usage); |
| @@ -200,7 +207,7 @@ void hiddev_report_event(struct hid_device *hid, struct hid_report *report) | |||
| 200 | uref.report_type = | 207 | uref.report_type = |
| 201 | (type == HID_INPUT_REPORT) ? HID_REPORT_TYPE_INPUT : | 208 | (type == HID_INPUT_REPORT) ? HID_REPORT_TYPE_INPUT : |
| 202 | ((type == HID_OUTPUT_REPORT) ? HID_REPORT_TYPE_OUTPUT : | 209 | ((type == HID_OUTPUT_REPORT) ? HID_REPORT_TYPE_OUTPUT : |
| 203 | ((type == HID_FEATURE_REPORT) ? HID_REPORT_TYPE_FEATURE:0)); | 210 | ((type == HID_FEATURE_REPORT) ? HID_REPORT_TYPE_FEATURE : 0)); |
| 204 | uref.report_id = report->id; | 211 | uref.report_id = report->id; |
| 205 | uref.field_index = HID_FIELD_INDEX_NONE; | 212 | uref.field_index = HID_FIELD_INDEX_NONE; |
| 206 | 213 | ||
| @@ -213,7 +220,9 @@ static int hiddev_fasync(int fd, struct file *file, int on) | |||
| 213 | { | 220 | { |
| 214 | int retval; | 221 | int retval; |
| 215 | struct hiddev_list *list = file->private_data; | 222 | struct hiddev_list *list = file->private_data; |
| 223 | |||
| 216 | retval = fasync_helper(fd, file, on, &list->fasync); | 224 | retval = fasync_helper(fd, file, on, &list->fasync); |
| 225 | |||
| 217 | return retval < 0 ? retval : 0; | 226 | return retval < 0 ? retval : 0; |
| 218 | } | 227 | } |
| 219 | 228 | ||
| @@ -224,14 +233,9 @@ static int hiddev_fasync(int fd, struct file *file, int on) | |||
| 224 | static int hiddev_release(struct inode * inode, struct file * file) | 233 | static int hiddev_release(struct inode * inode, struct file * file) |
| 225 | { | 234 | { |
| 226 | struct hiddev_list *list = file->private_data; | 235 | struct hiddev_list *list = file->private_data; |
| 227 | struct hiddev_list **listptr; | ||
| 228 | 236 | ||
| 229 | listptr = &list->hiddev->list; | ||
| 230 | hiddev_fasync(-1, file, 0); | 237 | hiddev_fasync(-1, file, 0); |
| 231 | 238 | list_del(&list->node); | |
| 232 | while (*listptr && (*listptr != list)) | ||
| 233 | listptr = &((*listptr)->next); | ||
| 234 | *listptr = (*listptr)->next; | ||
| 235 | 239 | ||
| 236 | if (!--list->hiddev->open) { | 240 | if (!--list->hiddev->open) { |
| 237 | if (list->hiddev->exist) | 241 | if (list->hiddev->exist) |
| @@ -248,7 +252,8 @@ static int hiddev_release(struct inode * inode, struct file * file) | |||
| 248 | /* | 252 | /* |
| 249 | * open file op | 253 | * open file op |
| 250 | */ | 254 | */ |
| 251 | static int hiddev_open(struct inode * inode, struct file * file) { | 255 | static int hiddev_open(struct inode *inode, struct file *file) |
| 256 | { | ||
| 252 | struct hiddev_list *list; | 257 | struct hiddev_list *list; |
| 253 | 258 | ||
| 254 | int i = iminor(inode) - HIDDEV_MINOR_BASE; | 259 | int i = iminor(inode) - HIDDEV_MINOR_BASE; |
| @@ -260,9 +265,7 @@ static int hiddev_open(struct inode * inode, struct file * file) { | |||
| 260 | return -ENOMEM; | 265 | return -ENOMEM; |
| 261 | 266 | ||
| 262 | list->hiddev = hiddev_table[i]; | 267 | list->hiddev = hiddev_table[i]; |
| 263 | list->next = hiddev_table[i]->list; | 268 | list_add_tail(&list->node, &hiddev_table[i]->list); |
| 264 | hiddev_table[i]->list = list; | ||
| 265 | |||
| 266 | file->private_data = list; | 269 | file->private_data = list; |
| 267 | 270 | ||
| 268 | if (!list->hiddev->open++) | 271 | if (!list->hiddev->open++) |
| @@ -362,6 +365,7 @@ static ssize_t hiddev_read(struct file * file, char __user * buffer, size_t coun | |||
| 362 | static unsigned int hiddev_poll(struct file *file, poll_table *wait) | 365 | static unsigned int hiddev_poll(struct file *file, poll_table *wait) |
| 363 | { | 366 | { |
| 364 | struct hiddev_list *list = file->private_data; | 367 | struct hiddev_list *list = file->private_data; |
| 368 | |||
| 365 | poll_wait(file, &list->hiddev->wait, wait); | 369 | poll_wait(file, &list->hiddev->wait, wait); |
| 366 | if (list->head != list->tail) | 370 | if (list->head != list->tail) |
| 367 | return POLLIN | POLLRDNORM; | 371 | return POLLIN | POLLRDNORM; |
| @@ -382,7 +386,7 @@ static int hiddev_ioctl(struct inode *inode, struct file *file, unsigned int cmd | |||
| 382 | struct hiddev_collection_info cinfo; | 386 | struct hiddev_collection_info cinfo; |
| 383 | struct hiddev_report_info rinfo; | 387 | struct hiddev_report_info rinfo; |
| 384 | struct hiddev_field_info finfo; | 388 | struct hiddev_field_info finfo; |
| 385 | struct hiddev_usage_ref_multi *uref_multi=NULL; | 389 | struct hiddev_usage_ref_multi *uref_multi = NULL; |
| 386 | struct hiddev_usage_ref *uref; | 390 | struct hiddev_usage_ref *uref; |
| 387 | struct hiddev_devinfo dinfo; | 391 | struct hiddev_devinfo dinfo; |
| 388 | struct hid_report *report; | 392 | struct hid_report *report; |
| @@ -764,15 +768,15 @@ int hiddev_connect(struct hid_device *hid) | |||
| 764 | } | 768 | } |
| 765 | 769 | ||
| 766 | init_waitqueue_head(&hiddev->wait); | 770 | init_waitqueue_head(&hiddev->wait); |
| 767 | 771 | INIT_LIST_HEAD(&hiddev->list); | |
| 768 | hiddev_table[hid->intf->minor - HIDDEV_MINOR_BASE] = hiddev; | ||
| 769 | |||
| 770 | hiddev->hid = hid; | 772 | hiddev->hid = hid; |
| 771 | hiddev->exist = 1; | 773 | hiddev->exist = 1; |
| 772 | 774 | ||
| 773 | hid->minor = hid->intf->minor; | 775 | hid->minor = hid->intf->minor; |
| 774 | hid->hiddev = hiddev; | 776 | hid->hiddev = hiddev; |
| 775 | 777 | ||
| 778 | hiddev_table[hid->intf->minor - HIDDEV_MINOR_BASE] = hiddev; | ||
| 779 | |||
| 776 | return 0; | 780 | return 0; |
| 777 | } | 781 | } |
| 778 | 782 | ||
