Commit 7bfb5dc1 authored by David Härdeman's avatar David Härdeman Committed by Mauro Carvalho Chehab

[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: default avatarDavid Härdeman <david@hardeman.nu>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 30cedcf3
...@@ -180,7 +180,6 @@ enum wbcir_rxstate { ...@@ -180,7 +180,6 @@ enum wbcir_rxstate {
enum wbcir_txstate { enum wbcir_txstate {
WBCIR_TXSTATE_INACTIVE = 0, WBCIR_TXSTATE_INACTIVE = 0,
WBCIR_TXSTATE_ACTIVE, WBCIR_TXSTATE_ACTIVE,
WBCIR_TXSTATE_DONE,
WBCIR_TXSTATE_ERROR WBCIR_TXSTATE_ERROR
}; };
...@@ -216,7 +215,6 @@ struct wbcir_data { ...@@ -216,7 +215,6 @@ struct wbcir_data {
u32 txlen; u32 txlen;
u32 txoff; u32 txoff;
u32 *txbuf; u32 *txbuf;
wait_queue_head_t txwaitq;
u8 txmask; u8 txmask;
u32 txcarrier; u32 txcarrier;
}; };
...@@ -424,11 +422,11 @@ wbcir_irq_tx(struct wbcir_data *data) ...@@ -424,11 +422,11 @@ wbcir_irq_tx(struct wbcir_data *data)
if (data->txstate == WBCIR_TXSTATE_ERROR) if (data->txstate == WBCIR_TXSTATE_ERROR)
/* Clear TX underrun bit */ /* Clear TX underrun bit */
outb(WBCIR_TX_UNDERRUN, data->sbase + WBCIR_REG_SP3_ASCR); outb(WBCIR_TX_UNDERRUN, data->sbase + WBCIR_REG_SP3_ASCR);
else
data->txstate = WBCIR_TXSTATE_DONE;
wbcir_set_irqmask(data, WBCIR_IRQ_RX | WBCIR_IRQ_ERR); wbcir_set_irqmask(data, WBCIR_IRQ_RX | WBCIR_IRQ_ERR);
led_trigger_event(data->txtrigger, LED_OFF); led_trigger_event(data->txtrigger, LED_OFF);
wake_up(&data->txwaitq); kfree(data->txbuf);
data->txbuf = NULL;
data->txstate = WBCIR_TXSTATE_INACTIVE;
} else if (data->txoff == data->txlen) { } else if (data->txoff == data->txlen) {
/* At the end of transmission, tell the hw before last byte */ /* At the end of transmission, tell the hw before last byte */
outsb(data->sbase + WBCIR_REG_SP3_TXDATA, bytes, used - 1); outsb(data->sbase + WBCIR_REG_SP3_TXDATA, bytes, used - 1);
...@@ -579,43 +577,37 @@ wbcir_txmask(struct rc_dev *dev, u32 mask) ...@@ -579,43 +577,37 @@ wbcir_txmask(struct rc_dev *dev, u32 mask)
} }
static int static int
wbcir_tx(struct rc_dev *dev, unsigned *buf, unsigned count) wbcir_tx(struct rc_dev *dev, unsigned *b, unsigned count)
{ {
struct wbcir_data *data = dev->priv; struct wbcir_data *data = dev->priv;
unsigned *buf;
unsigned i; unsigned i;
unsigned long flags; unsigned long flags;
buf = kmalloc(count * sizeof(*b), GFP_KERNEL);
if (!buf)
return -ENOMEM;
/* Convert values to multiples of 10us */
for (i = 0; i < count; i++)
buf[i] = DIV_ROUND_CLOSEST(b[i], 10);
/* Not sure if this is possible, but better safe than sorry */ /* Not sure if this is possible, but better safe than sorry */
spin_lock_irqsave(&data->spinlock, flags); spin_lock_irqsave(&data->spinlock, flags);
if (data->txstate != WBCIR_TXSTATE_INACTIVE) { if (data->txstate != WBCIR_TXSTATE_INACTIVE) {
spin_unlock_irqrestore(&data->spinlock, flags); spin_unlock_irqrestore(&data->spinlock, flags);
kfree(buf);
return -EBUSY; return -EBUSY;
} }
/* Convert values to multiples of 10us */
for (i = 0; i < count; i++)
buf[i] = DIV_ROUND_CLOSEST(buf[i], 10);
/* Fill the TX fifo once, the irq handler will do the rest */ /* Fill the TX fifo once, the irq handler will do the rest */
data->txbuf = buf; data->txbuf = buf;
data->txlen = count; data->txlen = count;
data->txoff = 0; data->txoff = 0;
wbcir_irq_tx(data); wbcir_irq_tx(data);
/* Wait for the TX to complete */
while (data->txstate == WBCIR_TXSTATE_ACTIVE) {
spin_unlock_irqrestore(&data->spinlock, flags);
wait_event(data->txwaitq, data->txstate != WBCIR_TXSTATE_ACTIVE);
spin_lock_irqsave(&data->spinlock, flags);
}
/* We're done */ /* We're done */
if (data->txstate == WBCIR_TXSTATE_ERROR)
count = -EAGAIN;
data->txstate = WBCIR_TXSTATE_INACTIVE;
data->txbuf = NULL;
spin_unlock_irqrestore(&data->spinlock, flags); spin_unlock_irqrestore(&data->spinlock, flags);
return count; return count;
} }
...@@ -927,13 +919,11 @@ wbcir_init_hw(struct wbcir_data *data) ...@@ -927,13 +919,11 @@ wbcir_init_hw(struct wbcir_data *data)
ir_raw_event_reset(data->dev); ir_raw_event_reset(data->dev);
ir_raw_event_handle(data->dev); ir_raw_event_handle(data->dev);
/* /* Clear TX state */
* Check TX state, if we did a suspend/resume cycle while TX was
* active, we will have a process waiting in txwaitq.
*/
if (data->txstate == WBCIR_TXSTATE_ACTIVE) { if (data->txstate == WBCIR_TXSTATE_ACTIVE) {
data->txstate = WBCIR_TXSTATE_ERROR; kfree(data->txbuf);
wake_up(&data->txwaitq); data->txbuf = NULL;
data->txstate = WBCIR_TXSTATE_INACTIVE;
} }
/* Enable interrupts */ /* Enable interrupts */
...@@ -974,7 +964,6 @@ wbcir_probe(struct pnp_dev *device, const struct pnp_device_id *dev_id) ...@@ -974,7 +964,6 @@ wbcir_probe(struct pnp_dev *device, const struct pnp_device_id *dev_id)
pnp_set_drvdata(device, data); pnp_set_drvdata(device, data);
spin_lock_init(&data->spinlock); spin_lock_init(&data->spinlock);
init_waitqueue_head(&data->txwaitq);
data->ebase = pnp_port_start(device, 0); data->ebase = pnp_port_start(device, 0);
data->wbase = pnp_port_start(device, 1); data->wbase = pnp_port_start(device, 1);
data->sbase = pnp_port_start(device, 2); data->sbase = pnp_port_start(device, 2);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment