Message ID | 200909101934.50283.mb@bu3sch.de (mailing list archive) |
---|---|
State | Not Applicable, archived |
Headers | show |
On Thu, Sep 10, 2009 at 7:34 PM, Michael Buesch <mb@bu3sch.de> wrote: > From: Albert Herranz <albert_herranz@yahoo.es> > > This adds support for Soft-MAC SDIO devices to b43. > The driver still lacks some fixes for SDIO devices, so it's currently > marked as BROKEN. Is it actually completely broken; or already testable, just incomplete? > > Signed-off-by: Albert Herranz <albert_herranz@yahoo.es> > Signed-off-by: Michael Buesch <mb@bu3sch.de> > > --- > > Depends on the SSB SDIO patch. > > > Index: wireless-testing/drivers/net/wireless/b43/Kconfig > =================================================================== > --- wireless-testing.orig/drivers/net/wireless/b43/Kconfig    2009-09-10 19:23:09.000000000 +0200 > +++ wireless-testing/drivers/net/wireless/b43/Kconfig  2009-09-10 19:33:24.000000000 +0200 > @@ -61,11 +61,28 @@ config B43_PCMCIA > >      If unsure, say N. > > +config B43_SDIO > +    bool "Broadcom 43xx SDIO device support (EXPERIMENTAL)" > +    depends on B43 && SSB_SDIOHOST_POSSIBLE && EXPERIMENTAL && BROKEN > +    select SSB_SDIOHOST > +    ---help--- > +     Broadcom 43xx device support for Soft-MAC SDIO devices. > + > +     With this config option you can drive Soft-MAC b43 cards with a > +     Secure Digital I/O interface. > +     This includes the WLAN daughter card found on the Nintendo Wii > +     video game console. > +     Note that this does not support Broadcom 43xx Full-MAC devices. > + > +     It's safe to select Y here, even if you don't have a B43 SDIO device. > + > +     If unsure, say N. > + >  # Data transfers to the device via PIO > -# This is only needed on PCMCIA devices. All others can do DMA properly. > +# This is only needed on PCMCIA and SDIO devices. All others can do DMA properly. >  config B43_PIO >     bool > -    depends on B43 && (B43_PCMCIA || B43_FORCE_PIO) > +    depends on B43 && (B43_SDIO || B43_PCMCIA || B43_FORCE_PIO) >     select SSB_BLOCKIO >     default y > > Index: wireless-testing/drivers/net/wireless/b43/Makefile > =================================================================== > --- wireless-testing.orig/drivers/net/wireless/b43/Makefile   2009-09-10 19:23:09.000000000 +0200 > +++ wireless-testing/drivers/net/wireless/b43/Makefile  2009-09-10 19:23:20.000000000 +0200 > @@ -16,6 +16,7 @@ b43-$(CONFIG_B43_PIO)     += pio.o >  b43-y              += rfkill.o >  b43-$(CONFIG_B43_LEDS)     += leds.o >  b43-$(CONFIG_B43_PCMCIA)    += pcmcia.o > +b43-$(CONFIG_B43_SDIO)     += sdio.o >  b43-$(CONFIG_B43_DEBUG)         += debugfs.o > >  obj-$(CONFIG_B43)        += b43.o > Index: wireless-testing/drivers/net/wireless/b43/main.c > =================================================================== > --- wireless-testing.orig/drivers/net/wireless/b43/main.c    2009-09-10 19:23:09.000000000 +0200 > +++ wireless-testing/drivers/net/wireless/b43/main.c   2009-09-10 19:23:20.000000000 +0200 > @@ -8,6 +8,9 @@ >  Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org> >  Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch> > > +  SDIO support > +  Copyright (c) 2009 Albert Herranz <albert_herranz@yahoo.es> > + >  Some parts of the code in this file are derived from the ipw2200 >  driver  Copyright(c) 2003 - 2004 Intel Corporation. > > @@ -53,6 +56,8 @@ >  #include "xmit.h" >  #include "lo.h" >  #include "pcmcia.h" > +#include "sdio.h" > +#include <linux/mmc/sdio_func.h> > >  MODULE_DESCRIPTION("Broadcom B43 wireless driver"); >  MODULE_AUTHOR("Martin Langer"); > @@ -1587,7 +1592,7 @@ static void b43_beacon_update_trigger_wo >     mutex_lock(&wl->mutex); >     dev = wl->current_dev; >     if (likely(dev && (b43_status(dev) >= B43_STAT_INITIALIZED))) { > -        if (0 /*FIXME dev->dev->bus->bustype == SSB_BUSTYPE_SDIO*/) { > +        if (dev->dev->bus->bustype == SSB_BUSTYPE_SDIO) { >             /* wl->mutex is enough. */ >             b43_do_beacon_update_trigger_work(dev); >             mmiowb(); > @@ -1905,6 +1910,27 @@ static irqreturn_t b43_interrupt_handler >     return ret; >  } > > +/* SDIO interrupt handler. This runs in process context. */ > +static void b43_sdio_interrupt_handler(struct b43_wldev *dev) > +{ > +    struct b43_wl *wl = dev->wl; > +    struct sdio_func *func = dev->dev->bus->host_sdio; > +    irqreturn_t ret; > + > +    if (unlikely(b43_status(dev) < B43_STAT_STARTED)) > +        return; > + > +    mutex_lock(&wl->mutex); > +    sdio_release_host(func); > + > +    ret = b43_do_interrupt(dev); > +    if (ret == IRQ_WAKE_THREAD) > +        b43_do_interrupt_thread(dev); > + > +    sdio_claim_host(func); > +    mutex_unlock(&wl->mutex); > +} > + >  void b43_do_release_fw(struct b43_firmware_file *fw) >  { >     release_firmware(fw->data); > @@ -3828,7 +3854,7 @@ redo: > >     /* Disable interrupts on the device. */ >     b43_set_status(dev, B43_STAT_INITIALIZED); > -    if (0 /*FIXME dev->dev->bus->bustype == SSB_BUSTYPE_SDIO*/) { > +    if (dev->dev->bus->bustype == SSB_BUSTYPE_SDIO) { >         /* wl->mutex is locked. That is enough. */ >         b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, 0); >         b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); /* Flush */ > @@ -3858,7 +3884,10 @@ redo: >         dev_kfree_skb(skb_dequeue(&wl->tx_queue)); > >     b43_mac_suspend(dev); > -    free_irq(dev->dev->irq, dev); > +    if (dev->dev->bus->bustype == SSB_BUSTYPE_SDIO) > +        b43_sdio_free_irq(dev); > +    else > +        free_irq(dev->dev->irq, dev); >     b43_leds_exit(dev); >     b43dbg(wl, "Wireless interface stopped\n"); > > @@ -3873,12 +3902,20 @@ static int b43_wireless_core_start(struc >     B43_WARN_ON(b43_status(dev) != B43_STAT_INITIALIZED); > >     drain_txstatus_queue(dev); > -    err = request_threaded_irq(dev->dev->irq, b43_interrupt_handler, > -                  b43_interrupt_thread_handler, > -                  IRQF_SHARED, KBUILD_MODNAME, dev); > -    if (err) { > -        b43err(dev->wl, "Cannot request IRQ-%d\n", dev->dev->irq); > -        goto out; > +    if (dev->dev->bus->bustype == SSB_BUSTYPE_SDIO) { > +        err = b43_sdio_request_irq(dev, b43_sdio_interrupt_handler); > +        if (err) { > +            b43err(dev->wl, "Cannot request SDIO IRQ\n"); > +            goto out; > +        } > +    } else { > +        err = request_threaded_irq(dev->dev->irq, b43_interrupt_handler, > +                      b43_interrupt_thread_handler, > +                      IRQF_SHARED, KBUILD_MODNAME, dev); > +        if (err) { > +            b43err(dev->wl, "Cannot request IRQ-%d\n", dev->dev->irq); > +            goto out; > +        } >     } > >     /* We are ready to run. */ > @@ -4270,7 +4307,9 @@ static int b43_wireless_core_init(struct >     /* Maximum Contention Window */ >     b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_MAXCONT, 0x3FF); > > -    if ((dev->dev->bus->bustype == SSB_BUSTYPE_PCMCIA) || B43_FORCE_PIO) { > +    if ((dev->dev->bus->bustype == SSB_BUSTYPE_PCMCIA) || > +      (dev->dev->bus->bustype == SSB_BUSTYPE_SDIO) || > +      B43_FORCE_PIO) { >         dev->__using_pio_transfers = 1; >         err = b43_pio_init(dev); >     } else { > @@ -4944,7 +4983,7 @@ static struct ssb_driver b43_ssb_driver >  static void b43_print_driverinfo(void) >  { >     const char *feat_pci = "", *feat_pcmcia = "", *feat_nphy = "", > -          *feat_leds = ""; > +          *feat_leds = "", *feat_sdio = ""; > >  #ifdef CONFIG_B43_PCI_AUTOSELECT >     feat_pci = "P"; > @@ -4958,11 +4997,14 @@ static void b43_print_driverinfo(void) >  #ifdef CONFIG_B43_LEDS >     feat_leds = "L"; >  #endif > +#ifdef CONFIG_B43_SDIO > +    feat_sdio = "S"; > +#endif >     printk(KERN_INFO "Broadcom 43xx driver loaded " > -        "[ Features: %s%s%s%s, Firmware-ID: " > +        "[ Features: %s%s%s%s%s, Firmware-ID: " >        B43_SUPPORTED_FIRMWARE_ID " ]\n", >        feat_pci, feat_pcmcia, feat_nphy, > -        feat_leds); > +        feat_leds, feat_sdio); >  } > >  static int __init b43_init(void) > @@ -4973,13 +5015,18 @@ static int __init b43_init(void) >     err = b43_pcmcia_init(); >     if (err) >         goto err_dfs_exit; > -    err = ssb_driver_register(&b43_ssb_driver); > +    err = b43_sdio_init(); >     if (err) >         goto err_pcmcia_exit; > +    err = ssb_driver_register(&b43_ssb_driver); > +    if (err) > +        goto err_sdio_exit; >     b43_print_driverinfo(); > >     return err; > > +err_sdio_exit: > +    b43_sdio_exit(); >  err_pcmcia_exit: >     b43_pcmcia_exit(); >  err_dfs_exit: > @@ -4990,6 +5037,7 @@ err_dfs_exit: >  static void __exit b43_exit(void) >  { >     ssb_driver_unregister(&b43_ssb_driver); > +    b43_sdio_exit(); >     b43_pcmcia_exit(); >     b43_debugfs_exit(); >  } > Index: wireless-testing/drivers/net/wireless/b43/sdio.c > =================================================================== > --- /dev/null  1970-01-01 00:00:00.000000000 +0000 > +++ wireless-testing/drivers/net/wireless/b43/sdio.c   2009-09-10 19:23:20.000000000 +0200 > @@ -0,0 +1,197 @@ > +/* > + * Broadcom B43 wireless driver > + * > + * SDIO over Sonics Silicon Backplane bus glue for b43. > + * > + * Copyright (C) 2009 Albert Herranz > + * Copyright (C) 2009 Michael Buesch <mb@bu3sch.de> > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation; either version 2 of the License, or (at > + * your option) any later version. > + */ > + > +#include <linux/kernel.h> > +#include <linux/mmc/card.h> > +#include <linux/mmc/sdio_func.h> > +#include <linux/mmc/sdio_ids.h> > +#include <linux/ssb/ssb.h> > + > +#include "sdio.h" > +#include "b43.h" > + > + > +#define HNBU_CHIPID       0x01   /* vendor & device id */ > + > +#define B43_SDIO_BLOCK_SIZE   64    /* rx fifo max size in bytes */ > + > + > +static const struct b43_sdio_quirk { > +    u16 vendor; > +    u16 device; > +    unsigned int quirks; > +} b43_sdio_quirks[] = { > +    { 0x14E4, 0x4318, SSB_QUIRK_SDIO_READ_AFTER_WRITE32, }, > +    { }, > +}; > + > + > +static unsigned int b43_sdio_get_quirks(u16 vendor, u16 device) > +{ > +    const struct b43_sdio_quirk *q; > + > +    for (q = b43_sdio_quirks; q->quirks; q++) { > +        if (vendor == q->vendor && device == q->device) > +            return q->quirks; > +    } > + > +    return 0; > +} > + > +static void b43_sdio_interrupt_dispatcher(struct sdio_func *func) > +{ > +    struct b43_sdio *sdio = sdio_get_drvdata(func); > +    struct b43_wldev *dev = sdio->irq_handler_opaque; > + > +    sdio->irq_handler(dev); > +} > + > +int b43_sdio_request_irq(struct b43_wldev *dev, > +             void (*handler)(struct b43_wldev *dev)) > +{ > +    struct ssb_bus *bus = dev->dev->bus; > +    struct sdio_func *func = bus->host_sdio; > +    struct b43_sdio *sdio = sdio_get_drvdata(func); > +    int err; > + > +    sdio->irq_handler_opaque = dev; > +    sdio->irq_handler = handler; > +    sdio_claim_host(func); > +    err = sdio_claim_irq(func, b43_sdio_interrupt_dispatcher); > +    sdio_release_host(func); > + > +    return err; > +} > + > +void b43_sdio_free_irq(struct b43_wldev *dev) > +{ > +    struct ssb_bus *bus = dev->dev->bus; > +    struct sdio_func *func = bus->host_sdio; > +    struct b43_sdio *sdio = sdio_get_drvdata(func); > + > +    sdio_claim_host(func); > +    sdio_release_irq(func); > +    sdio_release_host(func); > +    sdio->irq_handler_opaque = NULL; > +    sdio->irq_handler = NULL; > +} > + > +static int b43_sdio_probe(struct sdio_func *func, > +             const struct sdio_device_id *id) > +{ > +    struct b43_sdio *sdio; > +    struct sdio_func_tuple *tuple; > +    u16 vendor = 0, device = 0; > +    int error; > + > +    /* Look for the card chip identifier. */ > +    tuple = func->tuples; > +    while (tuple) { > +        switch (tuple->code) { > +        case 0x80: > +            switch (tuple->data[0]) { > +            case HNBU_CHIPID: > +                if (tuple->size != 5) > +                    break; > +                vendor = tuple->data[1] | (tuple->data[2]<<8); > +                device = tuple->data[3] | (tuple->data[4]<<8); > +                dev_info(&func->dev, "Chip ID %04x:%04x\n", > +                     vendor, device); > +                break; > +            default: > +                break; > +            } > +            break; > +        default: > +            break; > +        } > +        tuple = tuple->next; > +    } > +    if (!vendor || !device) { > +        error = -ENODEV; > +        goto out; > +    } > + > +    sdio_claim_host(func); > +    error = sdio_set_block_size(func, B43_SDIO_BLOCK_SIZE); > +    if (error) { > +        dev_err(&func->dev, "failed to set block size to %u bytes," > +            " error %d\n", B43_SDIO_BLOCK_SIZE, error); > +        goto err_release_host; > +    } > +    error = sdio_enable_func(func); > +    if (error) { > +        dev_err(&func->dev, "failed to enable func, error %d\n", error); > +        goto err_release_host; > +    } > +    sdio_release_host(func); > + > +    sdio = kzalloc(sizeof(*sdio), GFP_KERNEL); > +    if (!sdio) { > +        error = -ENOMEM; > +        dev_err(&func->dev, "failed to allocate ssb bus\n"); > +        goto err_disable_func; > +    } > +    error = ssb_bus_sdiobus_register(&sdio->ssb, func, > +                     b43_sdio_get_quirks(vendor, device)); > +    if (error) { > +        dev_err(&func->dev, "failed to register ssb sdio bus," > +            " error %d\n", error); > +        goto err_free_ssb; > +    } > +    sdio_set_drvdata(func, sdio); > + > +    return 0; > + > +err_free_ssb: > +    kfree(sdio); > +err_disable_func: > +    sdio_disable_func(func); > +err_release_host: > +    sdio_release_host(func); > +out: > +    return error; > +} > + > +static void b43_sdio_remove(struct sdio_func *func) > +{ > +    struct b43_sdio *sdio = sdio_get_drvdata(func); > + > +    ssb_bus_unregister(&sdio->ssb); > +    sdio_disable_func(func); > +    kfree(sdio); > +    sdio_set_drvdata(func, NULL); > +} > + > +static const struct sdio_device_id b43_sdio_ids[] = { > +    { SDIO_DEVICE(0x02d0, 0x044b) }, /* Nintendo Wii WLAN daughter card */ > +    { }, > +}; > + > +static struct sdio_driver b43_sdio_driver = { > +    .name      = "b43-sdio", > +    .id_table    = b43_sdio_ids, > +    .probe      = b43_sdio_probe, > +    .remove     = b43_sdio_remove, > +}; > + > +int b43_sdio_init(void) > +{ > +    return sdio_register_driver(&b43_sdio_driver); > +} > + > +void b43_sdio_exit(void) > +{ > +    sdio_unregister_driver(&b43_sdio_driver); > +} > Index: wireless-testing/drivers/net/wireless/b43/sdio.h > =================================================================== > --- /dev/null  1970-01-01 00:00:00.000000000 +0000 > +++ wireless-testing/drivers/net/wireless/b43/sdio.h   2009-09-10 19:23:20.000000000 +0200 > @@ -0,0 +1,45 @@ > +#ifndef B43_SDIO_H_ > +#define B43_SDIO_H_ > + > +#include <linux/ssb/ssb.h> > + > +struct b43_wldev; > + > + > +#ifdef CONFIG_B43_SDIO > + > +struct b43_sdio { > +    struct ssb_bus ssb; > +    void *irq_handler_opaque; > +    void (*irq_handler)(struct b43_wldev *dev); > +}; > + > +int b43_sdio_request_irq(struct b43_wldev *dev, > +             void (*handler)(struct b43_wldev *dev)); > +void b43_sdio_free_irq(struct b43_wldev *dev); > + > +int b43_sdio_init(void); > +void b43_sdio_exit(void); > + > + > +#else /* CONFIG_B43_SDIO */ > + > + > +int b43_sdio_request_irq(struct b43_wldev *dev, > +             void (*handler)(struct b43_wldev *dev)) > +{ > +    return -ENODEV; > +} > +void b43_sdio_free_irq(struct b43_wldev *dev) > +{ > +} > +static inline int b43_sdio_init(void) > +{ > +    return 0; > +} > +static inline void b43_sdio_exit(void) > +{ > +} > + > +#endif /* CONFIG_B43_SDIO */ > +#endif /* B43_SDIO_H_ */ > > > -- > Greetings, Michael. > _______________________________________________ > Bcm43xx-dev mailing list > Bcm43xx-dev@lists.berlios.de > https://lists.berlios.de/mailman/listinfo/bcm43xx-dev >
--- El jue, 10/9/09, Gábor Stefanik <netrolller.3d@gmail.com> escribió: > > This adds support for Soft-MAC SDIO devices to b43. > > The driver still lacks some fixes for SDIO devices, so > it's currently > > marked as BROKEN. > > Is it actually completely broken; or already testable, just > incomplete? > It doesn't work yet as posted to the ML. So I'd say, it is not testable. We'll work to bring it into an usable form, then mark it unbroken. Cheers, Albert -- To unsubscribe from this list: send the line "unsubscribe linux-wireless" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On Thursday 10 September 2009 23:23:19 Gábor Stefanik wrote: > On Thu, Sep 10, 2009 at 7:34 PM, Michael Buesch <mb@bu3sch.de> wrote: > > From: Albert Herranz <albert_herranz@yahoo.es> > > > > This adds support for Soft-MAC SDIO devices to b43. > > The driver still lacks some fixes for SDIO devices, so it's currently > > marked as BROKEN. > > Is it actually completely broken; or already testable, just incomplete? incomplete
Index: wireless-testing/drivers/net/wireless/b43/Kconfig =================================================================== --- wireless-testing.orig/drivers/net/wireless/b43/Kconfig 2009-09-10 19:23:09.000000000 +0200 +++ wireless-testing/drivers/net/wireless/b43/Kconfig 2009-09-10 19:33:24.000000000 +0200 @@ -61,11 +61,28 @@ config B43_PCMCIA If unsure, say N. +config B43_SDIO + bool "Broadcom 43xx SDIO device support (EXPERIMENTAL)" + depends on B43 && SSB_SDIOHOST_POSSIBLE && EXPERIMENTAL && BROKEN + select SSB_SDIOHOST + ---help--- + Broadcom 43xx device support for Soft-MAC SDIO devices. + + With this config option you can drive Soft-MAC b43 cards with a + Secure Digital I/O interface. + This includes the WLAN daughter card found on the Nintendo Wii + video game console. + Note that this does not support Broadcom 43xx Full-MAC devices. + + It's safe to select Y here, even if you don't have a B43 SDIO device. + + If unsure, say N. + # Data transfers to the device via PIO -# This is only needed on PCMCIA devices. All others can do DMA properly. +# This is only needed on PCMCIA and SDIO devices. All others can do DMA properly. config B43_PIO bool - depends on B43 && (B43_PCMCIA || B43_FORCE_PIO) + depends on B43 && (B43_SDIO || B43_PCMCIA || B43_FORCE_PIO) select SSB_BLOCKIO default y Index: wireless-testing/drivers/net/wireless/b43/Makefile =================================================================== --- wireless-testing.orig/drivers/net/wireless/b43/Makefile 2009-09-10 19:23:09.000000000 +0200 +++ wireless-testing/drivers/net/wireless/b43/Makefile 2009-09-10 19:23:20.000000000 +0200 @@ -16,6 +16,7 @@ b43-$(CONFIG_B43_PIO) += pio.o b43-y += rfkill.o b43-$(CONFIG_B43_LEDS) += leds.o b43-$(CONFIG_B43_PCMCIA) += pcmcia.o +b43-$(CONFIG_B43_SDIO) += sdio.o b43-$(CONFIG_B43_DEBUG) += debugfs.o obj-$(CONFIG_B43) += b43.o Index: wireless-testing/drivers/net/wireless/b43/main.c =================================================================== --- wireless-testing.orig/drivers/net/wireless/b43/main.c 2009-09-10 19:23:09.000000000 +0200 +++ wireless-testing/drivers/net/wireless/b43/main.c 2009-09-10 19:23:20.000000000 +0200 @@ -8,6 +8,9 @@ Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org> Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch> + SDIO support + Copyright (c) 2009 Albert Herranz <albert_herranz@yahoo.es> + Some parts of the code in this file are derived from the ipw2200 driver Copyright(c) 2003 - 2004 Intel Corporation. @@ -53,6 +56,8 @@ #include "xmit.h" #include "lo.h" #include "pcmcia.h" +#include "sdio.h" +#include <linux/mmc/sdio_func.h> MODULE_DESCRIPTION("Broadcom B43 wireless driver"); MODULE_AUTHOR("Martin Langer"); @@ -1587,7 +1592,7 @@ static void b43_beacon_update_trigger_wo mutex_lock(&wl->mutex); dev = wl->current_dev; if (likely(dev && (b43_status(dev) >= B43_STAT_INITIALIZED))) { - if (0 /*FIXME dev->dev->bus->bustype == SSB_BUSTYPE_SDIO*/) { + if (dev->dev->bus->bustype == SSB_BUSTYPE_SDIO) { /* wl->mutex is enough. */ b43_do_beacon_update_trigger_work(dev); mmiowb(); @@ -1905,6 +1910,27 @@ static irqreturn_t b43_interrupt_handler return ret; } +/* SDIO interrupt handler. This runs in process context. */ +static void b43_sdio_interrupt_handler(struct b43_wldev *dev) +{ + struct b43_wl *wl = dev->wl; + struct sdio_func *func = dev->dev->bus->host_sdio; + irqreturn_t ret; + + if (unlikely(b43_status(dev) < B43_STAT_STARTED)) + return; + + mutex_lock(&wl->mutex); + sdio_release_host(func); + + ret = b43_do_interrupt(dev); + if (ret == IRQ_WAKE_THREAD) + b43_do_interrupt_thread(dev); + + sdio_claim_host(func); + mutex_unlock(&wl->mutex); +} + void b43_do_release_fw(struct b43_firmware_file *fw) { release_firmware(fw->data); @@ -3828,7 +3854,7 @@ redo: /* Disable interrupts on the device. */ b43_set_status(dev, B43_STAT_INITIALIZED); - if (0 /*FIXME dev->dev->bus->bustype == SSB_BUSTYPE_SDIO*/) { + if (dev->dev->bus->bustype == SSB_BUSTYPE_SDIO) { /* wl->mutex is locked. That is enough. */ b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, 0); b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); /* Flush */ @@ -3858,7 +3884,10 @@ redo: dev_kfree_skb(skb_dequeue(&wl->tx_queue)); b43_mac_suspend(dev); - free_irq(dev->dev->irq, dev); + if (dev->dev->bus->bustype == SSB_BUSTYPE_SDIO) + b43_sdio_free_irq(dev); + else + free_irq(dev->dev->irq, dev); b43_leds_exit(dev); b43dbg(wl, "Wireless interface stopped\n"); @@ -3873,12 +3902,20 @@ static int b43_wireless_core_start(struc B43_WARN_ON(b43_status(dev) != B43_STAT_INITIALIZED); drain_txstatus_queue(dev); - err = request_threaded_irq(dev->dev->irq, b43_interrupt_handler, - b43_interrupt_thread_handler, - IRQF_SHARED, KBUILD_MODNAME, dev); - if (err) { - b43err(dev->wl, "Cannot request IRQ-%d\n", dev->dev->irq); - goto out; + if (dev->dev->bus->bustype == SSB_BUSTYPE_SDIO) { + err = b43_sdio_request_irq(dev, b43_sdio_interrupt_handler); + if (err) { + b43err(dev->wl, "Cannot request SDIO IRQ\n"); + goto out; + } + } else { + err = request_threaded_irq(dev->dev->irq, b43_interrupt_handler, + b43_interrupt_thread_handler, + IRQF_SHARED, KBUILD_MODNAME, dev); + if (err) { + b43err(dev->wl, "Cannot request IRQ-%d\n", dev->dev->irq); + goto out; + } } /* We are ready to run. */ @@ -4270,7 +4307,9 @@ static int b43_wireless_core_init(struct /* Maximum Contention Window */ b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_MAXCONT, 0x3FF); - if ((dev->dev->bus->bustype == SSB_BUSTYPE_PCMCIA) || B43_FORCE_PIO) { + if ((dev->dev->bus->bustype == SSB_BUSTYPE_PCMCIA) || + (dev->dev->bus->bustype == SSB_BUSTYPE_SDIO) || + B43_FORCE_PIO) { dev->__using_pio_transfers = 1; err = b43_pio_init(dev); } else { @@ -4944,7 +4983,7 @@ static struct ssb_driver b43_ssb_driver static void b43_print_driverinfo(void) { const char *feat_pci = "", *feat_pcmcia = "", *feat_nphy = "", - *feat_leds = ""; + *feat_leds = "", *feat_sdio = ""; #ifdef CONFIG_B43_PCI_AUTOSELECT feat_pci = "P"; @@ -4958,11 +4997,14 @@ static void b43_print_driverinfo(void) #ifdef CONFIG_B43_LEDS feat_leds = "L"; #endif +#ifdef CONFIG_B43_SDIO + feat_sdio = "S"; +#endif printk(KERN_INFO "Broadcom 43xx driver loaded " - "[ Features: %s%s%s%s, Firmware-ID: " + "[ Features: %s%s%s%s%s, Firmware-ID: " B43_SUPPORTED_FIRMWARE_ID " ]\n", feat_pci, feat_pcmcia, feat_nphy, - feat_leds); + feat_leds, feat_sdio); } static int __init b43_init(void) @@ -4973,13 +5015,18 @@ static int __init b43_init(void) err = b43_pcmcia_init(); if (err) goto err_dfs_exit; - err = ssb_driver_register(&b43_ssb_driver); + err = b43_sdio_init(); if (err) goto err_pcmcia_exit; + err = ssb_driver_register(&b43_ssb_driver); + if (err) + goto err_sdio_exit; b43_print_driverinfo(); return err; +err_sdio_exit: + b43_sdio_exit(); err_pcmcia_exit: b43_pcmcia_exit(); err_dfs_exit: @@ -4990,6 +5037,7 @@ err_dfs_exit: static void __exit b43_exit(void) { ssb_driver_unregister(&b43_ssb_driver); + b43_sdio_exit(); b43_pcmcia_exit(); b43_debugfs_exit(); } Index: wireless-testing/drivers/net/wireless/b43/sdio.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ wireless-testing/drivers/net/wireless/b43/sdio.c 2009-09-10 19:23:20.000000000 +0200 @@ -0,0 +1,197 @@ +/* + * Broadcom B43 wireless driver + * + * SDIO over Sonics Silicon Backplane bus glue for b43. + * + * Copyright (C) 2009 Albert Herranz + * Copyright (C) 2009 Michael Buesch <mb@bu3sch.de> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + */ + +#include <linux/kernel.h> +#include <linux/mmc/card.h> +#include <linux/mmc/sdio_func.h> +#include <linux/mmc/sdio_ids.h> +#include <linux/ssb/ssb.h> + +#include "sdio.h" +#include "b43.h" + + +#define HNBU_CHIPID 0x01 /* vendor & device id */ + +#define B43_SDIO_BLOCK_SIZE 64 /* rx fifo max size in bytes */ + + +static const struct b43_sdio_quirk { + u16 vendor; + u16 device; + unsigned int quirks; +} b43_sdio_quirks[] = { + { 0x14E4, 0x4318, SSB_QUIRK_SDIO_READ_AFTER_WRITE32, }, + { }, +}; + + +static unsigned int b43_sdio_get_quirks(u16 vendor, u16 device) +{ + const struct b43_sdio_quirk *q; + + for (q = b43_sdio_quirks; q->quirks; q++) { + if (vendor == q->vendor && device == q->device) + return q->quirks; + } + + return 0; +} + +static void b43_sdio_interrupt_dispatcher(struct sdio_func *func) +{ + struct b43_sdio *sdio = sdio_get_drvdata(func); + struct b43_wldev *dev = sdio->irq_handler_opaque; + + sdio->irq_handler(dev); +} + +int b43_sdio_request_irq(struct b43_wldev *dev, + void (*handler)(struct b43_wldev *dev)) +{ + struct ssb_bus *bus = dev->dev->bus; + struct sdio_func *func = bus->host_sdio; + struct b43_sdio *sdio = sdio_get_drvdata(func); + int err; + + sdio->irq_handler_opaque = dev; + sdio->irq_handler = handler; + sdio_claim_host(func); + err = sdio_claim_irq(func, b43_sdio_interrupt_dispatcher); + sdio_release_host(func); + + return err; +} + +void b43_sdio_free_irq(struct b43_wldev *dev) +{ + struct ssb_bus *bus = dev->dev->bus; + struct sdio_func *func = bus->host_sdio; + struct b43_sdio *sdio = sdio_get_drvdata(func); + + sdio_claim_host(func); + sdio_release_irq(func); + sdio_release_host(func); + sdio->irq_handler_opaque = NULL; + sdio->irq_handler = NULL; +} + +static int b43_sdio_probe(struct sdio_func *func, + const struct sdio_device_id *id) +{ + struct b43_sdio *sdio; + struct sdio_func_tuple *tuple; + u16 vendor = 0, device = 0; + int error; + + /* Look for the card chip identifier. */ + tuple = func->tuples; + while (tuple) { + switch (tuple->code) { + case 0x80: + switch (tuple->data[0]) { + case HNBU_CHIPID: + if (tuple->size != 5) + break; + vendor = tuple->data[1] | (tuple->data[2]<<8); + device = tuple->data[3] | (tuple->data[4]<<8); + dev_info(&func->dev, "Chip ID %04x:%04x\n", + vendor, device); + break; + default: + break; + } + break; + default: + break; + } + tuple = tuple->next; + } + if (!vendor || !device) { + error = -ENODEV; + goto out; + } + + sdio_claim_host(func); + error = sdio_set_block_size(func, B43_SDIO_BLOCK_SIZE); + if (error) { + dev_err(&func->dev, "failed to set block size to %u bytes," + " error %d\n", B43_SDIO_BLOCK_SIZE, error); + goto err_release_host; + } + error = sdio_enable_func(func); + if (error) { + dev_err(&func->dev, "failed to enable func, error %d\n", error); + goto err_release_host; + } + sdio_release_host(func); + + sdio = kzalloc(sizeof(*sdio), GFP_KERNEL); + if (!sdio) { + error = -ENOMEM; + dev_err(&func->dev, "failed to allocate ssb bus\n"); + goto err_disable_func; + } + error = ssb_bus_sdiobus_register(&sdio->ssb, func, + b43_sdio_get_quirks(vendor, device)); + if (error) { + dev_err(&func->dev, "failed to register ssb sdio bus," + " error %d\n", error); + goto err_free_ssb; + } + sdio_set_drvdata(func, sdio); + + return 0; + +err_free_ssb: + kfree(sdio); +err_disable_func: + sdio_disable_func(func); +err_release_host: + sdio_release_host(func); +out: + return error; +} + +static void b43_sdio_remove(struct sdio_func *func) +{ + struct b43_sdio *sdio = sdio_get_drvdata(func); + + ssb_bus_unregister(&sdio->ssb); + sdio_disable_func(func); + kfree(sdio); + sdio_set_drvdata(func, NULL); +} + +static const struct sdio_device_id b43_sdio_ids[] = { + { SDIO_DEVICE(0x02d0, 0x044b) }, /* Nintendo Wii WLAN daughter card */ + { }, +}; + +static struct sdio_driver b43_sdio_driver = { + .name = "b43-sdio", + .id_table = b43_sdio_ids, + .probe = b43_sdio_probe, + .remove = b43_sdio_remove, +}; + +int b43_sdio_init(void) +{ + return sdio_register_driver(&b43_sdio_driver); +} + +void b43_sdio_exit(void) +{ + sdio_unregister_driver(&b43_sdio_driver); +} Index: wireless-testing/drivers/net/wireless/b43/sdio.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ wireless-testing/drivers/net/wireless/b43/sdio.h 2009-09-10 19:23:20.000000000 +0200 @@ -0,0 +1,45 @@ +#ifndef B43_SDIO_H_ +#define B43_SDIO_H_ + +#include <linux/ssb/ssb.h> + +struct b43_wldev; + + +#ifdef CONFIG_B43_SDIO + +struct b43_sdio { + struct ssb_bus ssb; + void *irq_handler_opaque; + void (*irq_handler)(struct b43_wldev *dev); +}; + +int b43_sdio_request_irq(struct b43_wldev *dev, + void (*handler)(struct b43_wldev *dev)); +void b43_sdio_free_irq(struct b43_wldev *dev); + +int b43_sdio_init(void); +void b43_sdio_exit(void); + + +#else /* CONFIG_B43_SDIO */ + + +int b43_sdio_request_irq(struct b43_wldev *dev, + void (*handler)(struct b43_wldev *dev)) +{ + return -ENODEV; +} +void b43_sdio_free_irq(struct b43_wldev *dev) +{ +} +static inline int b43_sdio_init(void) +{ + return 0; +} +static inline void b43_sdio_exit(void) +{ +} + +#endif /* CONFIG_B43_SDIO */ +#endif /* B43_SDIO_H_ */