diff options
| -rw-r--r-- | drivers/hid/usbhid/hid-core.c | 31 | ||||
| -rw-r--r-- | drivers/hid/usbhid/hid-pidff.c | 5 | ||||
| -rw-r--r-- | drivers/hid/usbhid/usbhid.h | 2 | ||||
| -rw-r--r-- | include/linux/hid.h | 6 |
4 files changed, 37 insertions, 7 deletions
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index 07840df56c63..1ae047cd4fa1 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c | |||
| @@ -232,13 +232,16 @@ static void hid_irq_in(struct urb *urb) | |||
| 232 | static int hid_submit_out(struct hid_device *hid) | 232 | static int hid_submit_out(struct hid_device *hid) |
| 233 | { | 233 | { |
| 234 | struct hid_report *report; | 234 | struct hid_report *report; |
| 235 | char *raw_report; | ||
| 235 | struct usbhid_device *usbhid = hid->driver_data; | 236 | struct usbhid_device *usbhid = hid->driver_data; |
| 236 | 237 | ||
| 237 | report = usbhid->out[usbhid->outtail]; | 238 | report = usbhid->out[usbhid->outtail].report; |
| 239 | raw_report = usbhid->out[usbhid->outtail].raw_report; | ||
| 238 | 240 | ||
| 239 | hid_output_report(report, usbhid->outbuf); | ||
| 240 | usbhid->urbout->transfer_buffer_length = ((report->size - 1) >> 3) + 1 + (report->id > 0); | 241 | usbhid->urbout->transfer_buffer_length = ((report->size - 1) >> 3) + 1 + (report->id > 0); |
| 241 | usbhid->urbout->dev = hid_to_usb_dev(hid); | 242 | usbhid->urbout->dev = hid_to_usb_dev(hid); |
| 243 | memcpy(usbhid->outbuf, raw_report, usbhid->urbout->transfer_buffer_length); | ||
| 244 | kfree(raw_report); | ||
| 242 | 245 | ||
| 243 | dbg_hid("submitting out urb\n"); | 246 | dbg_hid("submitting out urb\n"); |
| 244 | 247 | ||
| @@ -254,17 +257,20 @@ static int hid_submit_ctrl(struct hid_device *hid) | |||
| 254 | { | 257 | { |
| 255 | struct hid_report *report; | 258 | struct hid_report *report; |
| 256 | unsigned char dir; | 259 | unsigned char dir; |
| 260 | char *raw_report; | ||
| 257 | int len; | 261 | int len; |
| 258 | struct usbhid_device *usbhid = hid->driver_data; | 262 | struct usbhid_device *usbhid = hid->driver_data; |
| 259 | 263 | ||
| 260 | report = usbhid->ctrl[usbhid->ctrltail].report; | 264 | report = usbhid->ctrl[usbhid->ctrltail].report; |
| 265 | raw_report = usbhid->ctrl[usbhid->ctrltail].raw_report; | ||
| 261 | dir = usbhid->ctrl[usbhid->ctrltail].dir; | 266 | dir = usbhid->ctrl[usbhid->ctrltail].dir; |
| 262 | 267 | ||
| 263 | len = ((report->size - 1) >> 3) + 1 + (report->id > 0); | 268 | len = ((report->size - 1) >> 3) + 1 + (report->id > 0); |
| 264 | if (dir == USB_DIR_OUT) { | 269 | if (dir == USB_DIR_OUT) { |
| 265 | hid_output_report(report, usbhid->ctrlbuf); | ||
| 266 | usbhid->urbctrl->pipe = usb_sndctrlpipe(hid_to_usb_dev(hid), 0); | 270 | usbhid->urbctrl->pipe = usb_sndctrlpipe(hid_to_usb_dev(hid), 0); |
| 267 | usbhid->urbctrl->transfer_buffer_length = len; | 271 | usbhid->urbctrl->transfer_buffer_length = len; |
| 272 | memcpy(usbhid->ctrlbuf, raw_report, len); | ||
| 273 | kfree(raw_report); | ||
| 268 | } else { | 274 | } else { |
| 269 | int maxpacket, padlen; | 275 | int maxpacket, padlen; |
| 270 | 276 | ||
| @@ -401,6 +407,7 @@ void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, uns | |||
| 401 | int head; | 407 | int head; |
| 402 | unsigned long flags; | 408 | unsigned long flags; |
| 403 | struct usbhid_device *usbhid = hid->driver_data; | 409 | struct usbhid_device *usbhid = hid->driver_data; |
| 410 | int len = ((report->size - 1) >> 3) + 1 + (report->id > 0); | ||
| 404 | 411 | ||
| 405 | if ((hid->quirks & HID_QUIRK_NOGET) && dir == USB_DIR_IN) | 412 | if ((hid->quirks & HID_QUIRK_NOGET) && dir == USB_DIR_IN) |
| 406 | return; | 413 | return; |
| @@ -415,7 +422,14 @@ void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, uns | |||
| 415 | return; | 422 | return; |
| 416 | } | 423 | } |
| 417 | 424 | ||
| 418 | usbhid->out[usbhid->outhead] = report; | 425 | usbhid->out[usbhid->outhead].raw_report = kmalloc(len, GFP_ATOMIC); |
| 426 | if (!usbhid->out[usbhid->outhead].raw_report) { | ||
| 427 | spin_unlock_irqrestore(&usbhid->outlock, flags); | ||
| 428 | warn("output queueing failed"); | ||
| 429 | return; | ||
| 430 | } | ||
| 431 | hid_output_report(report, usbhid->out[usbhid->outhead].raw_report); | ||
| 432 | usbhid->out[usbhid->outhead].report = report; | ||
| 419 | usbhid->outhead = head; | 433 | usbhid->outhead = head; |
| 420 | 434 | ||
| 421 | if (!test_and_set_bit(HID_OUT_RUNNING, &usbhid->iofl)) | 435 | if (!test_and_set_bit(HID_OUT_RUNNING, &usbhid->iofl)) |
| @@ -434,6 +448,15 @@ void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, uns | |||
| 434 | return; | 448 | return; |
| 435 | } | 449 | } |
| 436 | 450 | ||
| 451 | if (dir == USB_DIR_OUT) { | ||
| 452 | usbhid->ctrl[usbhid->ctrlhead].raw_report = kmalloc(len, GFP_ATOMIC); | ||
| 453 | if (!usbhid->ctrl[usbhid->ctrlhead].raw_report) { | ||
| 454 | spin_unlock_irqrestore(&usbhid->ctrllock, flags); | ||
| 455 | warn("control queueing failed"); | ||
| 456 | return; | ||
| 457 | } | ||
| 458 | hid_output_report(report, usbhid->ctrl[usbhid->ctrlhead].raw_report); | ||
| 459 | } | ||
| 437 | usbhid->ctrl[usbhid->ctrlhead].report = report; | 460 | usbhid->ctrl[usbhid->ctrlhead].report = report; |
| 438 | usbhid->ctrl[usbhid->ctrlhead].dir = dir; | 461 | usbhid->ctrl[usbhid->ctrlhead].dir = dir; |
| 439 | usbhid->ctrlhead = head; | 462 | usbhid->ctrlhead = head; |
diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c index 011326178c06..484e3eec2f88 100644 --- a/drivers/hid/usbhid/hid-pidff.c +++ b/drivers/hid/usbhid/hid-pidff.c | |||
| @@ -397,7 +397,6 @@ static void pidff_set_condition_report(struct pidff_device *pidff, | |||
| 397 | effect->u.condition[i].left_saturation); | 397 | effect->u.condition[i].left_saturation); |
| 398 | pidff_set(&pidff->set_condition[PID_DEAD_BAND], | 398 | pidff_set(&pidff->set_condition[PID_DEAD_BAND], |
| 399 | effect->u.condition[i].deadband); | 399 | effect->u.condition[i].deadband); |
| 400 | usbhid_wait_io(pidff->hid); | ||
| 401 | usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_CONDITION], | 400 | usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_CONDITION], |
| 402 | USB_DIR_OUT); | 401 | USB_DIR_OUT); |
| 403 | } | 402 | } |
| @@ -512,7 +511,6 @@ static void pidff_playback_pid(struct pidff_device *pidff, int pid_id, int n) | |||
| 512 | pidff->effect_operation[PID_LOOP_COUNT].value[0] = n; | 511 | pidff->effect_operation[PID_LOOP_COUNT].value[0] = n; |
| 513 | } | 512 | } |
| 514 | 513 | ||
| 515 | usbhid_wait_io(pidff->hid); | ||
| 516 | usbhid_submit_report(pidff->hid, pidff->reports[PID_EFFECT_OPERATION], | 514 | usbhid_submit_report(pidff->hid, pidff->reports[PID_EFFECT_OPERATION], |
| 517 | USB_DIR_OUT); | 515 | USB_DIR_OUT); |
| 518 | } | 516 | } |
| @@ -548,6 +546,9 @@ static int pidff_erase_effect(struct input_dev *dev, int effect_id) | |||
| 548 | int pid_id = pidff->pid_id[effect_id]; | 546 | int pid_id = pidff->pid_id[effect_id]; |
| 549 | 547 | ||
| 550 | debug("starting to erase %d/%d", effect_id, pidff->pid_id[effect_id]); | 548 | debug("starting to erase %d/%d", effect_id, pidff->pid_id[effect_id]); |
| 549 | /* Wait for the queue to clear. We do not want a full fifo to | ||
| 550 | prevent the effect removal. */ | ||
| 551 | usbhid_wait_io(pidff->hid); | ||
| 551 | pidff_playback_pid(pidff, pid_id, 0); | 552 | pidff_playback_pid(pidff, pid_id, 0); |
| 552 | pidff_erase_pid(pidff, pid_id); | 553 | pidff_erase_pid(pidff, pid_id); |
| 553 | 554 | ||
diff --git a/drivers/hid/usbhid/usbhid.h b/drivers/hid/usbhid/usbhid.h index b47f991867e9..abedb13c623e 100644 --- a/drivers/hid/usbhid/usbhid.h +++ b/drivers/hid/usbhid/usbhid.h | |||
| @@ -67,7 +67,7 @@ struct usbhid_device { | |||
| 67 | spinlock_t ctrllock; /* Control fifo spinlock */ | 67 | spinlock_t ctrllock; /* Control fifo spinlock */ |
| 68 | 68 | ||
| 69 | struct urb *urbout; /* Output URB */ | 69 | struct urb *urbout; /* Output URB */ |
| 70 | struct hid_report *out[HID_CONTROL_FIFO_SIZE]; /* Output pipe fifo */ | 70 | struct hid_output_fifo out[HID_CONTROL_FIFO_SIZE]; /* Output pipe fifo */ |
| 71 | unsigned char outhead, outtail; /* Output pipe fifo head & tail */ | 71 | unsigned char outhead, outtail; /* Output pipe fifo head & tail */ |
| 72 | char *outbuf; /* Output buffer */ | 72 | char *outbuf; /* Output buffer */ |
| 73 | dma_addr_t outbuf_dma; /* Output buffer dma */ | 73 | dma_addr_t outbuf_dma; /* Output buffer dma */ |
diff --git a/include/linux/hid.h b/include/linux/hid.h index dcdef0bb4bba..f13bca2dd53b 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h | |||
| @@ -388,6 +388,12 @@ struct hid_report_enum { | |||
| 388 | struct hid_control_fifo { | 388 | struct hid_control_fifo { |
| 389 | unsigned char dir; | 389 | unsigned char dir; |
| 390 | struct hid_report *report; | 390 | struct hid_report *report; |
| 391 | char *raw_report; | ||
| 392 | }; | ||
| 393 | |||
| 394 | struct hid_output_fifo { | ||
| 395 | struct hid_report *report; | ||
| 396 | char *raw_report; | ||
| 391 | }; | 397 | }; |
| 392 | 398 | ||
| 393 | #define HID_CLAIMED_INPUT 1 | 399 | #define HID_CLAIMED_INPUT 1 |
