Date:2011-07-06 22:36:21 (9 years 2 months ago)
Author:Werner Almesberger
Commit:7fa3bd331029facef4464626aee9f351b386e45d
Message:atusb: added tentative interrupt support

Added the USB-to-interrupt logic. The approach is basically to have a
bulk URB that waits for an incoming interrupt notification and that
gets resubmitted whenever the interrupt is acknowledged.

We map enable/disable to an atomic count of the masking depth.

To do:
- convert printks to dev_dbg or remove them
- remove bulk URB on driver unload
- implement interrupt synchronization (via an 10 ms timer)
- don't make atusb_irq_enable call atusb_do_irq directly but start
a tasklet instead. Otherwise, we recurse on a spin lock held
somewhere in the interrupt handling infrastructure.

We send our first interrupt before at86rf230.c is ready to handle
it. This causes all further interrupts to be lost. As a work-around,
just clear IRQ_STATUS at the end of at86rf230_probe.

Signed-off-by: Werner Almesberger <werner@almesberger.net>
Files: drivers/ieee802154/at86rf230.c (1 diff)
drivers/spi/atusb.c (6 diffs)

Change Details

drivers/ieee802154/at86rf230.c
796796    if (rc)
797797        goto err_irq;
798798
799{
800uint8_t val;
801at86rf230_read_subreg(lp, RG_IRQ_STATUS, 0xff, 0, &val);
802}
799803    return rc;
800804
801805err_irq:
drivers/spi/atusb.c
1919#include <linux/module.h>
2020#include <linux/platform_device.h>
2121#include <linux/interrupt.h>
22#include <linux/atomic.h>
2223#include <linux/usb.h>
2324#include <linux/spi/spi.h>
2425#include <linux/spi/at86rf230.h>
...... 
4445    uint8_t atusb_hw_type;
4546    struct spi_master *master;
4647    int slave_irq;
48    struct urb *irq_urb;
49    uint8_t irq_buf; /* scratch space */
50    atomic_t pending; /* pending interrupts */
51    atomic_t masked; /* masking levels */
4752    struct at86rf230_platform_data platform_data;
4853    /* copy platform_data so that we can adapt .reset_data */
4954    struct spi_device *spi;
...... 
352357/* ----- Interrupt handling ------------------------------------------------ */
353358
354359
355#if 0
356static irqreturn_t atusb_irq(int irq, void *data)
360static void atusb_do_irq(struct atusb_local *atusb);
361
362static void atusb_irq_enable(struct atusb_local *atusb)
357363{
358    struct atusb_local *atusb = data;
364    printk(KERN_INFO "atusb_irq_enable\n");
365    if (atomic_dec_return(&atusb->masked))
366        return;
367    if (!atomic_add_unless(&atusb->pending, -1, 0))
368        return;
369    /* @@@ probably racy around here.
370       need to think this through some more - wa */
371    atusb_do_irq(atusb);
372}
359373
360    generic_handle_irq(atusb->slave_irq);
361    return IRQ_HANDLED;
374static void atusb_do_irq(struct atusb_local *atusb)
375{
376    printk(KERN_INFO "atusb_do_irq\n");
377    if (atomic_inc_return(&atusb->masked) == 1)
378        generic_handle_irq(atusb->slave_irq);
379    else
380        atomic_set(&atusb->pending, 1);
381    printk(KERN_INFO "atusb_do_irq out\n");
382    atusb_irq_enable(atusb);
362383}
363#endif
384
385static void atusb_irq(struct urb *urb)
386{
387    struct atusb_local *atusb = urb->context;
388
389    printk(KERN_INFO "atusb_irq (%d)\n", urb->status);
390    usb_free_urb(urb);
391    atusb->irq_urb = NULL;
392    atusb_do_irq(atusb);
393}
394
395static int atusb_arm_interrupt(struct atusb_local *atusb)
396{
397    struct usb_device *dev = atusb->udev;
398    struct urb *urb;
399    int retval = -ENOMEM;
400
401    BUG_ON(atusb->irq_urb);
402
403    printk(KERN_INFO "atusb_arm_interrupt\n");
404    urb = usb_alloc_urb(0, GFP_KERNEL);
405    if (!urb) {
406        dev_err(&dev->dev,
407            "atusb_arm_interrupt: usb_alloc_urb failed\n");
408        return -ENOMEM;
409    }
410
411    usb_fill_bulk_urb(urb, dev, usb_rcvbulkpipe(dev, 1),
412        &atusb->irq_buf, 1, atusb_irq, atusb);
413    atusb->irq_urb = urb;
414    retval = usb_submit_urb(urb, GFP_KERNEL);
415    if (!retval)
416        return 0;
417
418    dev_err(&dev->dev, "failed submitting bulk urb, error %d", retval);
419    retval = retval == -ENOMEM ? retval : -EIO;
420
421    usb_free_urb(urb);
422
423    return retval;
424}
425
426static void atusb_irq_ack(struct irq_data *data)
427{
428    struct atusb_local *atusb = irq_data_get_irq_chip_data(data);
429
430    printk(KERN_INFO "atusb_irq_ack\n");
431    atusb_arm_interrupt(atusb);
432}
433
364434static void atusb_irq_mask(struct irq_data *data)
365435{
366// struct atben_local *atusb = irq_data_get_irq_chip_data(data);
436    struct atusb_local *atusb = irq_data_get_irq_chip_data(data);
367437
368// disable_irq_nosync(atusb->usb_irq);
438    printk(KERN_INFO "atusb_irq_mask\n");
439    atomic_inc(&atusb->masked);
369440}
370441
371442static void atusb_irq_unmask(struct irq_data *data)
372443{
373// struct atben_local *atusb = irq_data_get_irq_chip_data(data);
444    struct atusb_local *atusb = irq_data_get_irq_chip_data(data);
374445
375// enable_irq(atusb->usb_irq);
446    printk(KERN_INFO "atusb_irq_unmask\n");
447    atusb_irq_enable(atusb);
376448}
377449
378450static struct irq_chip atusb_irq_chip = {
379451    .name = "atusb-slave",
380452    .irq_mask = atusb_irq_mask,
381453    .irq_unmask = atusb_irq_unmask,
454    .irq_ack = atusb_irq_ack,
382455};
383456
384457
...... 
534607    board_info.platform_data = &atusb->platform_data;
535608    board_info.irq = atusb->slave_irq;
536609
610    atomic_set(&atusb->masked, 0);
611    atomic_set(&atusb->pending, 0);
612    atusb_arm_interrupt(atusb);
613
537614    atusb->spi = spi_new_device(master, &board_info);
538615    if (!atusb->spi) {
539616        dev_info(&udev->dev, "can't create new device for %s\n",
...... 
552629    return 0;
553630
554631err_master:
632    /* @@@ kill interrupt URB */
555633    spi_master_put(atusb->master);
556634err_slave_irq:
557635    set_irq_chained_handler(atusb->slave_irq, NULL);
...... 
566644    struct atusb_local *atusb = usb_get_intfdata(interface);
567645    struct spi_master *master = atusb->master;
568646
647    /* @@@ kill interrupt URB */
569648    usb_set_intfdata(interface, NULL);
570649    usb_put_dev(atusb->udev);
571650

Archive Download the corresponding diff file



interactive