diff options
author | Sean Young <sean@mess.org> | 2012-09-28 03:44:29 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-10-07 08:03:35 -0400 |
commit | 48b0fa6afa7ee6a274e060564d2389ffea413762 (patch) | |
tree | 9fdedae472772dc35f34f5b3c42239d8fdef2f7d /drivers/media | |
parent | 947c48086623d9ca2207dd0434bd58458af4ba86 (diff) |
[media] iguanair: cannot send data from the stack
Note that the firmware already disables the receiver before transmit,
there is no need to do this from the driver.
Reported-by: Fengguang Wu <fengguang.wu@intel.com>
Signed-off-by: Sean Young <sean@mess.org>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media')
-rw-r--r-- | drivers/media/rc/iguanair.c | 147 |
1 files changed, 75 insertions, 72 deletions
diff --git a/drivers/media/rc/iguanair.c b/drivers/media/rc/iguanair.c index 1e4c68a5cecf..51d7057aca04 100644 --- a/drivers/media/rc/iguanair.c +++ b/drivers/media/rc/iguanair.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <media/rc-core.h> | 28 | #include <media/rc-core.h> |
29 | 29 | ||
30 | #define DRIVER_NAME "iguanair" | 30 | #define DRIVER_NAME "iguanair" |
31 | #define BUF_SIZE 152 | ||
31 | 32 | ||
32 | struct iguanair { | 33 | struct iguanair { |
33 | struct rc_dev *rc; | 34 | struct rc_dev *rc; |
@@ -35,26 +36,23 @@ struct iguanair { | |||
35 | struct device *dev; | 36 | struct device *dev; |
36 | struct usb_device *udev; | 37 | struct usb_device *udev; |
37 | 38 | ||
38 | int pipe_out; | ||
39 | uint16_t version; | 39 | uint16_t version; |
40 | uint8_t bufsize; | 40 | uint8_t bufsize; |
41 | uint8_t cycle_overhead; | ||
41 | 42 | ||
42 | struct mutex lock; | 43 | struct mutex lock; |
43 | 44 | ||
44 | /* receiver support */ | 45 | /* receiver support */ |
45 | bool receiver_on; | 46 | bool receiver_on; |
46 | dma_addr_t dma_in; | 47 | dma_addr_t dma_in, dma_out; |
47 | uint8_t *buf_in; | 48 | uint8_t *buf_in; |
48 | struct urb *urb_in; | 49 | struct urb *urb_in, *urb_out; |
49 | struct completion completion; | 50 | struct completion completion; |
50 | 51 | ||
51 | /* transmit support */ | 52 | /* transmit support */ |
52 | bool tx_overflow; | 53 | bool tx_overflow; |
53 | uint32_t carrier; | 54 | uint32_t carrier; |
54 | uint8_t cycle_overhead; | 55 | struct send_packet *packet; |
55 | uint8_t channels; | ||
56 | uint8_t busy4; | ||
57 | uint8_t busy7; | ||
58 | 56 | ||
59 | char name[64]; | 57 | char name[64]; |
60 | char phys[64]; | 58 | char phys[64]; |
@@ -73,7 +71,8 @@ struct iguanair { | |||
73 | #define DIR_IN 0xdc | 71 | #define DIR_IN 0xdc |
74 | #define DIR_OUT 0xcd | 72 | #define DIR_OUT 0xcd |
75 | 73 | ||
76 | #define MAX_PACKET_SIZE 8u | 74 | #define MAX_IN_PACKET 8u |
75 | #define MAX_OUT_PACKET (sizeof(struct send_packet) + BUF_SIZE) | ||
77 | #define TIMEOUT 1000 | 76 | #define TIMEOUT 1000 |
78 | #define RX_RESOLUTION 21333 | 77 | #define RX_RESOLUTION 21333 |
79 | 78 | ||
@@ -191,20 +190,25 @@ static void iguanair_rx(struct urb *urb) | |||
191 | dev_warn(ir->dev, "failed to resubmit urb: %d\n", rc); | 190 | dev_warn(ir->dev, "failed to resubmit urb: %d\n", rc); |
192 | } | 191 | } |
193 | 192 | ||
194 | static int iguanair_send(struct iguanair *ir, void *data, unsigned size) | 193 | static void iguanair_irq_out(struct urb *urb) |
195 | { | 194 | { |
196 | int rc, transferred; | 195 | struct iguanair *ir = urb->context; |
196 | |||
197 | if (urb->status) | ||
198 | dev_dbg(ir->dev, "Error: out urb status = %d\n", urb->status); | ||
199 | } | ||
200 | |||
201 | static int iguanair_send(struct iguanair *ir, unsigned size) | ||
202 | { | ||
203 | int rc; | ||
197 | 204 | ||
198 | INIT_COMPLETION(ir->completion); | 205 | INIT_COMPLETION(ir->completion); |
199 | 206 | ||
200 | rc = usb_interrupt_msg(ir->udev, ir->pipe_out, data, size, | 207 | ir->urb_out->transfer_buffer_length = size; |
201 | &transferred, TIMEOUT); | 208 | rc = usb_submit_urb(ir->urb_out, GFP_KERNEL); |
202 | if (rc) | 209 | if (rc) |
203 | return rc; | 210 | return rc; |
204 | 211 | ||
205 | if (transferred != size) | ||
206 | return -EIO; | ||
207 | |||
208 | if (wait_for_completion_timeout(&ir->completion, TIMEOUT) == 0) | 212 | if (wait_for_completion_timeout(&ir->completion, TIMEOUT) == 0) |
209 | return -ETIMEDOUT; | 213 | return -ETIMEDOUT; |
210 | 214 | ||
@@ -213,14 +217,13 @@ static int iguanair_send(struct iguanair *ir, void *data, unsigned size) | |||
213 | 217 | ||
214 | static int iguanair_get_features(struct iguanair *ir) | 218 | static int iguanair_get_features(struct iguanair *ir) |
215 | { | 219 | { |
216 | struct packet packet; | ||
217 | int rc; | 220 | int rc; |
218 | 221 | ||
219 | packet.start = 0; | 222 | ir->packet->header.start = 0; |
220 | packet.direction = DIR_OUT; | 223 | ir->packet->header.direction = DIR_OUT; |
221 | packet.cmd = CMD_GET_VERSION; | 224 | ir->packet->header.cmd = CMD_GET_VERSION; |
222 | 225 | ||
223 | rc = iguanair_send(ir, &packet, sizeof(packet)); | 226 | rc = iguanair_send(ir, sizeof(ir->packet->header)); |
224 | if (rc) { | 227 | if (rc) { |
225 | dev_info(ir->dev, "failed to get version\n"); | 228 | dev_info(ir->dev, "failed to get version\n"); |
226 | goto out; | 229 | goto out; |
@@ -235,17 +238,23 @@ static int iguanair_get_features(struct iguanair *ir) | |||
235 | ir->bufsize = 150; | 238 | ir->bufsize = 150; |
236 | ir->cycle_overhead = 65; | 239 | ir->cycle_overhead = 65; |
237 | 240 | ||
238 | packet.cmd = CMD_GET_BUFSIZE; | 241 | ir->packet->header.cmd = CMD_GET_BUFSIZE; |
239 | 242 | ||
240 | rc = iguanair_send(ir, &packet, sizeof(packet)); | 243 | rc = iguanair_send(ir, sizeof(ir->packet->header)); |
241 | if (rc) { | 244 | if (rc) { |
242 | dev_info(ir->dev, "failed to get buffer size\n"); | 245 | dev_info(ir->dev, "failed to get buffer size\n"); |
243 | goto out; | 246 | goto out; |
244 | } | 247 | } |
245 | 248 | ||
246 | packet.cmd = CMD_GET_FEATURES; | 249 | if (ir->bufsize > BUF_SIZE) { |
250 | dev_info(ir->dev, "buffer size %u larger than expected\n", | ||
251 | ir->bufsize); | ||
252 | ir->bufsize = BUF_SIZE; | ||
253 | } | ||
254 | |||
255 | ir->packet->header.cmd = CMD_GET_FEATURES; | ||
247 | 256 | ||
248 | rc = iguanair_send(ir, &packet, sizeof(packet)); | 257 | rc = iguanair_send(ir, sizeof(ir->packet->header)); |
249 | if (rc) { | 258 | if (rc) { |
250 | dev_info(ir->dev, "failed to get features\n"); | 259 | dev_info(ir->dev, "failed to get features\n"); |
251 | goto out; | 260 | goto out; |
@@ -257,13 +266,18 @@ out: | |||
257 | 266 | ||
258 | static int iguanair_receiver(struct iguanair *ir, bool enable) | 267 | static int iguanair_receiver(struct iguanair *ir, bool enable) |
259 | { | 268 | { |
260 | struct packet packet = { 0, DIR_OUT, enable ? | 269 | int rc; |
261 | CMD_RECEIVER_ON : CMD_RECEIVER_OFF }; | 270 | |
271 | ir->packet->header.start = 0; | ||
272 | ir->packet->header.direction = DIR_OUT; | ||
273 | ir->packet->header.cmd = enable ? CMD_RECEIVER_ON : CMD_RECEIVER_OFF; | ||
262 | 274 | ||
263 | if (enable) | 275 | if (enable) |
264 | ir_raw_event_reset(ir->rc); | 276 | ir_raw_event_reset(ir->rc); |
265 | 277 | ||
266 | return iguanair_send(ir, &packet, sizeof(packet)); | 278 | rc = iguanair_send(ir, sizeof(ir->packet->header)); |
279 | |||
280 | return rc; | ||
267 | } | 281 | } |
268 | 282 | ||
269 | /* | 283 | /* |
@@ -308,8 +322,8 @@ static int iguanair_set_tx_carrier(struct rc_dev *dev, uint32_t carrier) | |||
308 | fours = (cycles - sevens * 7) / 4; | 322 | fours = (cycles - sevens * 7) / 4; |
309 | 323 | ||
310 | /* magic happens here */ | 324 | /* magic happens here */ |
311 | ir->busy7 = (4 - sevens) * 2; | 325 | ir->packet->busy7 = (4 - sevens) * 2; |
312 | ir->busy4 = 110 - fours; | 326 | ir->packet->busy4 = 110 - fours; |
313 | } | 327 | } |
314 | 328 | ||
315 | mutex_unlock(&ir->lock); | 329 | mutex_unlock(&ir->lock); |
@@ -325,7 +339,7 @@ static int iguanair_set_tx_mask(struct rc_dev *dev, uint32_t mask) | |||
325 | return 4; | 339 | return 4; |
326 | 340 | ||
327 | mutex_lock(&ir->lock); | 341 | mutex_lock(&ir->lock); |
328 | ir->channels = mask; | 342 | ir->packet->channels = mask << 4; |
329 | mutex_unlock(&ir->lock); | 343 | mutex_unlock(&ir->lock); |
330 | 344 | ||
331 | return 0; | 345 | return 0; |
@@ -337,16 +351,9 @@ static int iguanair_tx(struct rc_dev *dev, unsigned *txbuf, unsigned count) | |||
337 | uint8_t space; | 351 | uint8_t space; |
338 | unsigned i, size, periods, bytes; | 352 | unsigned i, size, periods, bytes; |
339 | int rc; | 353 | int rc; |
340 | struct send_packet *packet; | ||
341 | 354 | ||
342 | mutex_lock(&ir->lock); | 355 | mutex_lock(&ir->lock); |
343 | 356 | ||
344 | packet = kmalloc(sizeof(*packet) + ir->bufsize, GFP_KERNEL); | ||
345 | if (!packet) { | ||
346 | rc = -ENOMEM; | ||
347 | goto out; | ||
348 | } | ||
349 | |||
350 | /* convert from us to carrier periods */ | 357 | /* convert from us to carrier periods */ |
351 | for (i = space = size = 0; i < count; i++) { | 358 | for (i = space = size = 0; i < count; i++) { |
352 | periods = DIV_ROUND_CLOSEST(txbuf[i] * ir->carrier, 1000000); | 359 | periods = DIV_ROUND_CLOSEST(txbuf[i] * ir->carrier, 1000000); |
@@ -356,11 +363,11 @@ static int iguanair_tx(struct rc_dev *dev, unsigned *txbuf, unsigned count) | |||
356 | break; | 363 | break; |
357 | } | 364 | } |
358 | while (periods > 127) { | 365 | while (periods > 127) { |
359 | packet->payload[size++] = 127 | space; | 366 | ir->packet->payload[size++] = 127 | space; |
360 | periods -= 127; | 367 | periods -= 127; |
361 | } | 368 | } |
362 | 369 | ||
363 | packet->payload[size++] = periods | space; | 370 | ir->packet->payload[size++] = periods | space; |
364 | space ^= 0x80; | 371 | space ^= 0x80; |
365 | } | 372 | } |
366 | 373 | ||
@@ -369,36 +376,19 @@ static int iguanair_tx(struct rc_dev *dev, unsigned *txbuf, unsigned count) | |||
369 | goto out; | 376 | goto out; |
370 | } | 377 | } |
371 | 378 | ||
372 | packet->header.start = 0; | 379 | ir->packet->header.start = 0; |
373 | packet->header.direction = DIR_OUT; | 380 | ir->packet->header.direction = DIR_OUT; |
374 | packet->header.cmd = CMD_SEND; | 381 | ir->packet->header.cmd = CMD_SEND; |
375 | packet->length = size; | 382 | ir->packet->length = size; |
376 | packet->channels = ir->channels << 4; | ||
377 | packet->busy7 = ir->busy7; | ||
378 | packet->busy4 = ir->busy4; | ||
379 | |||
380 | if (ir->receiver_on) { | ||
381 | rc = iguanair_receiver(ir, false); | ||
382 | if (rc) { | ||
383 | dev_warn(ir->dev, "disable receiver before transmit failed\n"); | ||
384 | goto out; | ||
385 | } | ||
386 | } | ||
387 | 383 | ||
388 | ir->tx_overflow = false; | 384 | ir->tx_overflow = false; |
389 | 385 | ||
390 | rc = iguanair_send(ir, packet, size + 8); | 386 | rc = iguanair_send(ir, sizeof(*ir->packet) + size); |
391 | 387 | ||
392 | if (rc == 0 && ir->tx_overflow) | 388 | if (rc == 0 && ir->tx_overflow) |
393 | rc = -EOVERFLOW; | 389 | rc = -EOVERFLOW; |
394 | 390 | ||
395 | if (ir->receiver_on) { | ||
396 | if (iguanair_receiver(ir, true)) | ||
397 | dev_warn(ir->dev, "re-enable receiver after transmit failed\n"); | ||
398 | } | ||
399 | |||
400 | out: | 391 | out: |
401 | kfree(packet); | ||
402 | mutex_unlock(&ir->lock); | 392 | mutex_unlock(&ir->lock); |
403 | 393 | ||
404 | return rc ? rc : count; | 394 | return rc ? rc : count; |
@@ -411,8 +401,6 @@ static int iguanair_open(struct rc_dev *rdev) | |||
411 | 401 | ||
412 | mutex_lock(&ir->lock); | 402 | mutex_lock(&ir->lock); |
413 | 403 | ||
414 | BUG_ON(ir->receiver_on); | ||
415 | |||
416 | rc = iguanair_receiver(ir, true); | 404 | rc = iguanair_receiver(ir, true); |
417 | if (rc == 0) | 405 | if (rc == 0) |
418 | ir->receiver_on = true; | 406 | ir->receiver_on = true; |
@@ -443,7 +431,7 @@ static int __devinit iguanair_probe(struct usb_interface *intf, | |||
443 | struct usb_device *udev = interface_to_usbdev(intf); | 431 | struct usb_device *udev = interface_to_usbdev(intf); |
444 | struct iguanair *ir; | 432 | struct iguanair *ir; |
445 | struct rc_dev *rc; | 433 | struct rc_dev *rc; |
446 | int ret, pipein; | 434 | int ret, pipein, pipeout; |
447 | struct usb_host_interface *idesc; | 435 | struct usb_host_interface *idesc; |
448 | 436 | ||
449 | ir = kzalloc(sizeof(*ir), GFP_KERNEL); | 437 | ir = kzalloc(sizeof(*ir), GFP_KERNEL); |
@@ -453,11 +441,14 @@ static int __devinit iguanair_probe(struct usb_interface *intf, | |||
453 | goto out; | 441 | goto out; |
454 | } | 442 | } |
455 | 443 | ||
456 | ir->buf_in = usb_alloc_coherent(udev, MAX_PACKET_SIZE, GFP_KERNEL, | 444 | ir->buf_in = usb_alloc_coherent(udev, MAX_IN_PACKET, GFP_KERNEL, |
457 | &ir->dma_in); | 445 | &ir->dma_in); |
446 | ir->packet = usb_alloc_coherent(udev, MAX_OUT_PACKET, GFP_KERNEL, | ||
447 | &ir->dma_out); | ||
458 | ir->urb_in = usb_alloc_urb(0, GFP_KERNEL); | 448 | ir->urb_in = usb_alloc_urb(0, GFP_KERNEL); |
449 | ir->urb_out = usb_alloc_urb(0, GFP_KERNEL); | ||
459 | 450 | ||
460 | if (!ir->buf_in || !ir->urb_in) { | 451 | if (!ir->buf_in || !ir->packet || !ir->urb_in || !ir->urb_out) { |
461 | ret = -ENOMEM; | 452 | ret = -ENOMEM; |
462 | goto out; | 453 | goto out; |
463 | } | 454 | } |
@@ -472,13 +463,18 @@ static int __devinit iguanair_probe(struct usb_interface *intf, | |||
472 | ir->rc = rc; | 463 | ir->rc = rc; |
473 | ir->dev = &intf->dev; | 464 | ir->dev = &intf->dev; |
474 | ir->udev = udev; | 465 | ir->udev = udev; |
475 | ir->pipe_out = usb_sndintpipe(udev, | ||
476 | idesc->endpoint[1].desc.bEndpointAddress); | ||
477 | mutex_init(&ir->lock); | 466 | mutex_init(&ir->lock); |
467 | |||
478 | init_completion(&ir->completion); | 468 | init_completion(&ir->completion); |
469 | pipeout = usb_sndintpipe(udev, | ||
470 | idesc->endpoint[1].desc.bEndpointAddress); | ||
471 | usb_fill_int_urb(ir->urb_out, udev, pipeout, ir->packet, MAX_OUT_PACKET, | ||
472 | iguanair_irq_out, ir, 1); | ||
473 | ir->urb_out->transfer_dma = ir->dma_out; | ||
474 | ir->urb_out->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; | ||
479 | 475 | ||
480 | pipein = usb_rcvintpipe(udev, idesc->endpoint[0].desc.bEndpointAddress); | 476 | pipein = usb_rcvintpipe(udev, idesc->endpoint[0].desc.bEndpointAddress); |
481 | usb_fill_int_urb(ir->urb_in, udev, pipein, ir->buf_in, MAX_PACKET_SIZE, | 477 | usb_fill_int_urb(ir->urb_in, udev, pipein, ir->buf_in, MAX_IN_PACKET, |
482 | iguanair_rx, ir, 1); | 478 | iguanair_rx, ir, 1); |
483 | ir->urb_in->transfer_dma = ir->dma_in; | 479 | ir->urb_in->transfer_dma = ir->dma_in; |
484 | ir->urb_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; | 480 | ir->urb_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP; |
@@ -528,11 +524,14 @@ static int __devinit iguanair_probe(struct usb_interface *intf, | |||
528 | return 0; | 524 | return 0; |
529 | out2: | 525 | out2: |
530 | usb_kill_urb(ir->urb_in); | 526 | usb_kill_urb(ir->urb_in); |
527 | usb_kill_urb(ir->urb_out); | ||
531 | out: | 528 | out: |
532 | if (ir) { | 529 | if (ir) { |
533 | usb_free_urb(ir->urb_in); | 530 | usb_free_urb(ir->urb_in); |
534 | usb_free_coherent(udev, MAX_PACKET_SIZE, ir->buf_in, | 531 | usb_free_urb(ir->urb_out); |
535 | ir->dma_in); | 532 | usb_free_coherent(udev, MAX_IN_PACKET, ir->buf_in, ir->dma_in); |
533 | usb_free_coherent(udev, MAX_OUT_PACKET, ir->packet, | ||
534 | ir->dma_out); | ||
536 | } | 535 | } |
537 | rc_free_device(rc); | 536 | rc_free_device(rc); |
538 | kfree(ir); | 537 | kfree(ir); |
@@ -546,8 +545,11 @@ static void __devexit iguanair_disconnect(struct usb_interface *intf) | |||
546 | rc_unregister_device(ir->rc); | 545 | rc_unregister_device(ir->rc); |
547 | usb_set_intfdata(intf, NULL); | 546 | usb_set_intfdata(intf, NULL); |
548 | usb_kill_urb(ir->urb_in); | 547 | usb_kill_urb(ir->urb_in); |
548 | usb_kill_urb(ir->urb_out); | ||
549 | usb_free_urb(ir->urb_in); | 549 | usb_free_urb(ir->urb_in); |
550 | usb_free_coherent(ir->udev, MAX_PACKET_SIZE, ir->buf_in, ir->dma_in); | 550 | usb_free_urb(ir->urb_out); |
551 | usb_free_coherent(ir->udev, MAX_IN_PACKET, ir->buf_in, ir->dma_in); | ||
552 | usb_free_coherent(ir->udev, MAX_OUT_PACKET, ir->packet, ir->dma_out); | ||
551 | kfree(ir); | 553 | kfree(ir); |
552 | } | 554 | } |
553 | 555 | ||
@@ -565,6 +567,7 @@ static int iguanair_suspend(struct usb_interface *intf, pm_message_t message) | |||
565 | } | 567 | } |
566 | 568 | ||
567 | usb_kill_urb(ir->urb_in); | 569 | usb_kill_urb(ir->urb_in); |
570 | usb_kill_urb(ir->urb_out); | ||
568 | 571 | ||
569 | mutex_unlock(&ir->lock); | 572 | mutex_unlock(&ir->lock); |
570 | 573 | ||