Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

[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
Loading
Loading
Loading
Loading
+18 −29
Original line number Original line Diff line number Diff line
@@ -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);