[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>
This commit is contained in:
committed by
Mauro Carvalho Chehab
parent
30cedcf34f
commit
7bfb5dc1cd
@@ -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 {
|
|||||||
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)
|
|||||||
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)
|
|||||||
}
|
}
|
||||||
|
|
||||||
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)
|
|||||||
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)
|
|||||||
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);
|
||||||
|
Reference in New Issue
Block a user