static int wbcir_tx(struct rc_dev *dev, unsigned *b, unsigned count) { struct wbcir_data *data = dev->priv; unsigned *buf; unsigned i; unsigned long flags; buf = kmalloc_array(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 */ spin_lock_irqsave(&data->spinlock, flags); if (data->txstate != WBCIR_TXSTATE_INACTIVE) { spin_unlock_irqrestore(&data->spinlock, flags); kfree(buf); return -EBUSY; } /* Fill the TX fifo once, the irq handler will do the rest */ data->txbuf = buf; data->txlen = count; data->txoff = 0; wbcir_irq_tx(data); /* We're done */ spin_unlock_irqrestore(&data->spinlock, flags); return count; }
static int wbcir_tx(struct rc_dev *dev, int *buf, u32 bufsize) { struct wbcir_data *data = dev->priv; u32 count; unsigned i; unsigned long flags; /* bufsize has been sanity checked by the caller */ count = bufsize / sizeof(int); /* Not sure if this is possible, but better safe than sorry */ spin_lock_irqsave(&data->spinlock, flags); if (data->txstate != WBCIR_TXSTATE_INACTIVE) { spin_unlock_irqrestore(&data->spinlock, flags); 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 */ data->txbuf = buf; data->txlen = count; data->txoff = 0; 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 */ if (data->txstate == WBCIR_TXSTATE_ERROR) count = -EAGAIN; data->txstate = WBCIR_TXSTATE_INACTIVE; data->txbuf = NULL; spin_unlock_irqrestore(&data->spinlock, flags); return count; }
static int wbcir_tx(struct rc_dev *dev, unsigned *buf, unsigned count) { struct wbcir_data *data = dev->priv; unsigned i; unsigned long flags; spin_lock_irqsave(&data->spinlock, flags); if (data->txstate != WBCIR_TXSTATE_INACTIVE) { spin_unlock_irqrestore(&data->spinlock, flags); return -EBUSY; } for (i = 0; i < count; i++) buf[i] = DIV_ROUND_CLOSEST(buf[i], 10); data->txbuf = buf; data->txlen = count; data->txoff = 0; wbcir_irq_tx(data); 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); } if (data->txstate == WBCIR_TXSTATE_ERROR) count = -EAGAIN; data->txstate = WBCIR_TXSTATE_INACTIVE; data->txbuf = NULL; spin_unlock_irqrestore(&data->spinlock, flags); return count; }
static irqreturn_t wbcir_irq_handler(int irqno, void *cookie) { struct pnp_dev *device = cookie; struct wbcir_data *data = pnp_get_drvdata(device); unsigned long flags; u8 status; spin_lock_irqsave(&data->spinlock, flags); wbcir_select_bank(data, WBCIR_BANK_0); status = inb(data->sbase + WBCIR_REG_SP3_EIR); status &= data->irqmask; if (!status) { spin_unlock_irqrestore(&data->spinlock, flags); return IRQ_NONE; } if (status & WBCIR_IRQ_ERR) { /* RX overflow? (read clears bit) */ if (inb(data->sbase + WBCIR_REG_SP3_LSR) & WBCIR_RX_OVERRUN) { data->rxstate = WBCIR_RXSTATE_ERROR; ir_raw_event_reset(data->dev); } /* TX underflow? */ if (inb(data->sbase + WBCIR_REG_SP3_ASCR) & WBCIR_TX_UNDERRUN) data->txstate = WBCIR_TXSTATE_ERROR; } if (status & WBCIR_IRQ_RX) wbcir_irq_rx(data, device); if (status & (WBCIR_IRQ_TX_LOW | WBCIR_IRQ_TX_EMPTY)) wbcir_irq_tx(data); spin_unlock_irqrestore(&data->spinlock, flags); return IRQ_HANDLED; }