Date:2011-07-07 01:12:03 (12 years 8 months ago)
Author:Werner Almesberger
Commit:eb1a51efda953658df691c467a6b1249e54c5dd8
Message:atusb: implement interrupt synchronization via a 10 ms delay timer

Writes to TRX_STATE may have to act as interrupt barriers. Since we
currently have no direct means for ensuring that host and atusb are
synchronized, we simply wait 10 ms, which should be sufficient to
receive any pending bulk data.

Moved the TRX_STATE change detection logic from atusb_transfer to
atusb_write and implemented the delay via a timer.

Signed-off-by: Werner Almesberger <werner@almesberger.net>
Files: drivers/spi/atusb.c (7 diffs)

Change Details

drivers/spi/atusb.c
1818#include <linux/kernel.h>
1919#include <linux/module.h>
2020#include <linux/platform_device.h>
21#include <linux/jiffies.h>
22#include <linux/timer.h>
2123#include <linux/interrupt.h>
2224#include <linux/usb.h>
2325#include <linux/spi/spi.h>
...... 
4749    struct urb *irq_urb;
4850    uint8_t irq_buf; /* scratch space */
4951    struct tasklet_struct task; /* interrupt delivery tasklet */
52    struct timer_list timer; /* delay, for interrupt synch */
5053    struct at86rf230_platform_data platform_data;
5154    /* copy platform_data so that we can adapt .reset_data */
5255    struct spi_device *spi;
...... 
152155    atusb_async_finish(urb);
153156}
154157
158static void atusb_timer(unsigned long data)
159{
160    struct urb *urb = (void *) data;
161
162    printk(KERN_INFO "atusb_timer\n");
163    atusb_async_finish(urb);
164}
165
166static void atusb_ctrl_cb_delayed(struct urb *urb)
167{
168    struct atusb_local *atusb = urb->context;
169
170    if (atusb_async_errchk(urb))
171        atusb_async_finish(urb);
172    else {
173        BUG_ON(timer_pending(&atusb->timer));
174        atusb->timer.expires = jiffies+msecs_to_jiffies(10);
175        atusb->timer.data = (unsigned long) urb;
176        add_timer(&atusb->timer);
177    }
178}
179
155180static void atusb_read_fb_cb(struct urb *urb)
156181{
157182    struct atusb_local *atusb = urb->context;
...... 
242267static int atusb_write(struct atusb_local *atusb,
243268    uint8_t tx0, uint8_t tx1, const uint8_t *tx, int len)
244269{
270    usb_complete_t cb = atusb_ctrl_cb;
271
245272    dev_info(&atusb->udev->dev, "atusb_write: tx[0] = 0x%x\n", tx0);
246273    dev_info(&atusb->udev->dev, "atusb_write: tx[1] = 0x%x\n", tx1);
274
275    /*
276     * The AT86RF230 driver sometimes requires a transceiver state
277     * transition to be an interrupt barrier. This is the case after
278     * writing FORCE_TX_ON to the TRX_CMD field in the TRX_STATE register.
279     *
280     * Since there is no other means of notification, we just decode the
281     * transfer and do a bit of pattern matching.
282     */
283    if (tx0 == (CMD_REG | CMD_WRITE | RG_TRX_STATE) &&
284        (tx1 & 0x1f) == STATE_FORCE_TX_ON)
285        cb = atusb_ctrl_cb_delayed;
286
247287    return submit_control_msg(atusb,
248288        ATUSB_SPI_WRITE, ATUSB_TO_DEV, tx0, tx1,
249        (uint8_t *) tx, len, atusb_ctrl_cb, atusb);
289        (uint8_t *) tx, len, cb, atusb);
250290}
251291
252292static int atusb_transfer(struct spi_device *spi, struct spi_message *msg)
...... 
318358                x[1]->tx_buf, x[1]->len);
319359        }
320360    }
321#if 0
322    /*
323     * The AT86RF230 driver sometimes requires a transceiver state
324     * transition to be an interrupt barrier. This is the case after
325     * writing FORCE_TX_ON to the TRX_CMD field in the TRX_STATE register.
326     *
327     * Since there is no other means of notification, we just decode the
328     * transfer and do a bit of pattern matching.
329     */
330    xfer = list_first_entry(&msg->transfers, struct spi_transfer,
331        transfer_list);
332    tx = xfer->tx_buf;
333    if (tx && xfer->len == 2 &&
334        tx[0] == (CMD_REG | CMD_WRITE | RG_TRX_STATE) &&
335        (tx[1] & 0x1f) == STATE_FORCE_TX_ON)
336        synchronize_irq(atusb->gpio_irq);
337#endif
338361    return retval;
339362
340363bad_req:
...... 
588611    board_info.platform_data = &atusb->platform_data;
589612    board_info.irq = atusb->slave_irq;
590613
614    init_timer(&atusb->timer);
615    atusb->timer.function = atusb_timer;
616
591617    tasklet_init(&atusb->task, atusb_tasklet, (unsigned long) atusb);
592618    tasklet_disable(&atusb->task);
593619    atusb_arm_interrupt(atusb);
...... 
638664    if (atusb->irq_urb)
639665        usb_kill_urb(atusb->irq_urb);
640666
667    BUG_ON(timer_pending(&atusb->timer));
668
641669    usb_set_intfdata(interface, NULL);
642670    usb_put_dev(atusb->udev);
643671

Archive Download the corresponding diff file



interactive