aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorDavid Härdeman <david@hardeman.nu>2012-08-25 16:46:58 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2012-09-25 13:08:46 -0400
commit7bfb5dc1cd7f6c98f85aff27b5091f9cbbc2932f (patch)
tree57fbb8688c2800ce810a15538bfb3f774cedd835 /drivers
parent30cedcf34f0309ea1ad6e0fdf7a52fcf37985658 (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.c47
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 {
180enum wbcir_txstate { 180enum 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
581static int 579static int
582wbcir_tx(struct rc_dev *dev, unsigned *buf, unsigned count) 580wbcir_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);