diff options
author | David Härdeman <david@hardeman.nu> | 2012-08-25 16:46:58 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-09-25 13:08:46 -0400 |
commit | 7bfb5dc1cd7f6c98f85aff27b5091f9cbbc2932f (patch) | |
tree | 57fbb8688c2800ce810a15538bfb3f774cedd835 /drivers | |
parent | 30cedcf34f0309ea1ad6e0fdf7a52fcf37985658 (diff) |
[media] winbond-cir: asynchronous tx
Change winbond-cir's tx support to be asynchronous and not to mess with
the TX buffer. Essentially the winbond-cir counterpart to the patch
Sean Young sent for iguanair.
Signed-off-by: David Härdeman <david@hardeman.nu>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/media/rc/winbond-cir.c | 47 |
1 files changed, 18 insertions, 29 deletions
diff --git a/drivers/media/rc/winbond-cir.c b/drivers/media/rc/winbond-cir.c index 29e6769b91a8..30ae1f24abc3 100644 --- a/drivers/media/rc/winbond-cir.c +++ b/drivers/media/rc/winbond-cir.c | |||
@@ -180,7 +180,6 @@ enum wbcir_rxstate { | |||
180 | enum wbcir_txstate { | 180 | enum wbcir_txstate { |
181 | WBCIR_TXSTATE_INACTIVE = 0, | 181 | WBCIR_TXSTATE_INACTIVE = 0, |
182 | WBCIR_TXSTATE_ACTIVE, | 182 | WBCIR_TXSTATE_ACTIVE, |
183 | WBCIR_TXSTATE_DONE, | ||
184 | WBCIR_TXSTATE_ERROR | 183 | WBCIR_TXSTATE_ERROR |
185 | }; | 184 | }; |
186 | 185 | ||
@@ -216,7 +215,6 @@ struct wbcir_data { | |||
216 | u32 txlen; | 215 | u32 txlen; |
217 | u32 txoff; | 216 | u32 txoff; |
218 | u32 *txbuf; | 217 | u32 *txbuf; |
219 | wait_queue_head_t txwaitq; | ||
220 | u8 txmask; | 218 | u8 txmask; |
221 | u32 txcarrier; | 219 | u32 txcarrier; |
222 | }; | 220 | }; |
@@ -424,11 +422,11 @@ wbcir_irq_tx(struct wbcir_data *data) | |||
424 | if (data->txstate == WBCIR_TXSTATE_ERROR) | 422 | if (data->txstate == WBCIR_TXSTATE_ERROR) |
425 | /* Clear TX underrun bit */ | 423 | /* Clear TX underrun bit */ |
426 | outb(WBCIR_TX_UNDERRUN, data->sbase + WBCIR_REG_SP3_ASCR); | 424 | outb(WBCIR_TX_UNDERRUN, data->sbase + WBCIR_REG_SP3_ASCR); |
427 | else | ||
428 | data->txstate = WBCIR_TXSTATE_DONE; | ||
429 | wbcir_set_irqmask(data, WBCIR_IRQ_RX | WBCIR_IRQ_ERR); | 425 | wbcir_set_irqmask(data, WBCIR_IRQ_RX | WBCIR_IRQ_ERR); |
430 | led_trigger_event(data->txtrigger, LED_OFF); | 426 | led_trigger_event(data->txtrigger, LED_OFF); |
431 | wake_up(&data->txwaitq); | 427 | kfree(data->txbuf); |
428 | data->txbuf = NULL; | ||
429 | data->txstate = WBCIR_TXSTATE_INACTIVE; | ||
432 | } else if (data->txoff == data->txlen) { | 430 | } else if (data->txoff == data->txlen) { |
433 | /* At the end of transmission, tell the hw before last byte */ | 431 | /* At the end of transmission, tell the hw before last byte */ |
434 | outsb(data->sbase + WBCIR_REG_SP3_TXDATA, bytes, used - 1); | 432 | outsb(data->sbase + WBCIR_REG_SP3_TXDATA, bytes, used - 1); |
@@ -579,43 +577,37 @@ wbcir_txmask(struct rc_dev *dev, u32 mask) | |||
579 | } | 577 | } |
580 | 578 | ||
581 | static int | 579 | static int |
582 | wbcir_tx(struct rc_dev *dev, unsigned *buf, unsigned count) | 580 | wbcir_tx(struct rc_dev *dev, unsigned *b, unsigned count) |
583 | { | 581 | { |
584 | struct wbcir_data *data = dev->priv; | 582 | struct wbcir_data *data = dev->priv; |
583 | unsigned *buf; | ||
585 | unsigned i; | 584 | unsigned i; |
586 | unsigned long flags; | 585 | unsigned long flags; |
587 | 586 | ||
587 | buf = kmalloc(count * sizeof(*b), GFP_KERNEL); | ||
588 | if (!buf) | ||
589 | return -ENOMEM; | ||
590 | |||
591 | /* Convert values to multiples of 10us */ | ||
592 | for (i = 0; i < count; i++) | ||
593 | buf[i] = DIV_ROUND_CLOSEST(b[i], 10); | ||
594 | |||
588 | /* Not sure if this is possible, but better safe than sorry */ | 595 | /* Not sure if this is possible, but better safe than sorry */ |
589 | spin_lock_irqsave(&data->spinlock, flags); | 596 | spin_lock_irqsave(&data->spinlock, flags); |
590 | if (data->txstate != WBCIR_TXSTATE_INACTIVE) { | 597 | if (data->txstate != WBCIR_TXSTATE_INACTIVE) { |
591 | spin_unlock_irqrestore(&data->spinlock, flags); | 598 | spin_unlock_irqrestore(&data->spinlock, flags); |
599 | kfree(buf); | ||
592 | return -EBUSY; | 600 | return -EBUSY; |
593 | } | 601 | } |
594 | 602 | ||
595 | /* Convert values to multiples of 10us */ | ||
596 | for (i = 0; i < count; i++) | ||
597 | buf[i] = DIV_ROUND_CLOSEST(buf[i], 10); | ||
598 | |||
599 | /* Fill the TX fifo once, the irq handler will do the rest */ | 603 | /* Fill the TX fifo once, the irq handler will do the rest */ |
600 | data->txbuf = buf; | 604 | data->txbuf = buf; |
601 | data->txlen = count; | 605 | data->txlen = count; |
602 | data->txoff = 0; | 606 | data->txoff = 0; |
603 | wbcir_irq_tx(data); | 607 | wbcir_irq_tx(data); |
604 | 608 | ||
605 | /* Wait for the TX to complete */ | ||
606 | while (data->txstate == WBCIR_TXSTATE_ACTIVE) { | ||
607 | spin_unlock_irqrestore(&data->spinlock, flags); | ||
608 | wait_event(data->txwaitq, data->txstate != WBCIR_TXSTATE_ACTIVE); | ||
609 | spin_lock_irqsave(&data->spinlock, flags); | ||
610 | } | ||
611 | |||
612 | /* We're done */ | 609 | /* We're done */ |
613 | if (data->txstate == WBCIR_TXSTATE_ERROR) | ||
614 | count = -EAGAIN; | ||
615 | data->txstate = WBCIR_TXSTATE_INACTIVE; | ||
616 | data->txbuf = NULL; | ||
617 | spin_unlock_irqrestore(&data->spinlock, flags); | 610 | spin_unlock_irqrestore(&data->spinlock, flags); |
618 | |||
619 | return count; | 611 | return count; |
620 | } | 612 | } |
621 | 613 | ||
@@ -927,13 +919,11 @@ wbcir_init_hw(struct wbcir_data *data) | |||
927 | ir_raw_event_reset(data->dev); | 919 | ir_raw_event_reset(data->dev); |
928 | ir_raw_event_handle(data->dev); | 920 | ir_raw_event_handle(data->dev); |
929 | 921 | ||
930 | /* | 922 | /* Clear TX state */ |
931 | * Check TX state, if we did a suspend/resume cycle while TX was | ||
932 | * active, we will have a process waiting in txwaitq. | ||
933 | */ | ||
934 | if (data->txstate == WBCIR_TXSTATE_ACTIVE) { | 923 | if (data->txstate == WBCIR_TXSTATE_ACTIVE) { |
935 | data->txstate = WBCIR_TXSTATE_ERROR; | 924 | kfree(data->txbuf); |
936 | wake_up(&data->txwaitq); | 925 | data->txbuf = NULL; |
926 | data->txstate = WBCIR_TXSTATE_INACTIVE; | ||
937 | } | 927 | } |
938 | 928 | ||
939 | /* Enable interrupts */ | 929 | /* Enable interrupts */ |
@@ -974,7 +964,6 @@ wbcir_probe(struct pnp_dev *device, const struct pnp_device_id *dev_id) | |||
974 | pnp_set_drvdata(device, data); | 964 | pnp_set_drvdata(device, data); |
975 | 965 | ||
976 | spin_lock_init(&data->spinlock); | 966 | spin_lock_init(&data->spinlock); |
977 | init_waitqueue_head(&data->txwaitq); | ||
978 | data->ebase = pnp_port_start(device, 0); | 967 | data->ebase = pnp_port_start(device, 0); |
979 | data->wbase = pnp_port_start(device, 1); | 968 | data->wbase = pnp_port_start(device, 1); |
980 | data->sbase = pnp_port_start(device, 2); | 969 | data->sbase = pnp_port_start(device, 2); |