linux/drivers/net/wireless/b43/sdio.c
<<
>>
Prefs
   1/*
   2 * Broadcom B43 wireless driver
   3 *
   4 * SDIO over Sonics Silicon Backplane bus glue for b43.
   5 *
   6 * Copyright (C) 2009 Albert Herranz
   7 * Copyright (C) 2009 Michael Buesch <m@bues.ch>
   8 *
   9 * This program is free software; you can redistribute it and/or modify
  10 * it under the terms of the GNU General Public License as published by
  11 * the Free Software Foundation; either version 2 of the License, or (at
  12 * your option) any later version.
  13 */
  14
  15#include <linux/kernel.h>
  16#include <linux/mmc/card.h>
  17#include <linux/mmc/sdio_func.h>
  18#include <linux/mmc/sdio_ids.h>
  19#include <linux/slab.h>
  20#include <linux/ssb/ssb.h>
  21
  22#include "sdio.h"
  23#include "b43.h"
  24
  25
  26#define HNBU_CHIPID             0x01    /* vendor & device id */
  27
  28#define B43_SDIO_BLOCK_SIZE     64      /* rx fifo max size in bytes */
  29
  30
  31static const struct b43_sdio_quirk {
  32        u16 vendor;
  33        u16 device;
  34        unsigned int quirks;
  35} b43_sdio_quirks[] = {
  36        { 0x14E4, 0x4318, SSB_QUIRK_SDIO_READ_AFTER_WRITE32, },
  37        { },
  38};
  39
  40
  41static unsigned int b43_sdio_get_quirks(u16 vendor, u16 device)
  42{
  43        const struct b43_sdio_quirk *q;
  44
  45        for (q = b43_sdio_quirks; q->quirks; q++) {
  46                if (vendor == q->vendor && device == q->device)
  47                        return q->quirks;
  48        }
  49
  50        return 0;
  51}
  52
  53static void b43_sdio_interrupt_dispatcher(struct sdio_func *func)
  54{
  55        struct b43_sdio *sdio = sdio_get_drvdata(func);
  56        struct b43_wldev *dev = sdio->irq_handler_opaque;
  57
  58        if (unlikely(b43_status(dev) < B43_STAT_STARTED))
  59                return;
  60
  61        sdio_release_host(func);
  62        sdio->irq_handler(dev);
  63        sdio_claim_host(func);
  64}
  65
  66int b43_sdio_request_irq(struct b43_wldev *dev,
  67                         void (*handler)(struct b43_wldev *dev))
  68{
  69        struct ssb_bus *bus = dev->dev->sdev->bus;
  70        struct sdio_func *func = bus->host_sdio;
  71        struct b43_sdio *sdio = sdio_get_drvdata(func);
  72        int err;
  73
  74        sdio->irq_handler_opaque = dev;
  75        sdio->irq_handler = handler;
  76        sdio_claim_host(func);
  77        err = sdio_claim_irq(func, b43_sdio_interrupt_dispatcher);
  78        sdio_release_host(func);
  79
  80        return err;
  81}
  82
  83void b43_sdio_free_irq(struct b43_wldev *dev)
  84{
  85        struct ssb_bus *bus = dev->dev->sdev->bus;
  86        struct sdio_func *func = bus->host_sdio;
  87        struct b43_sdio *sdio = sdio_get_drvdata(func);
  88
  89        sdio_claim_host(func);
  90        sdio_release_irq(func);
  91        sdio_release_host(func);
  92        sdio->irq_handler_opaque = NULL;
  93        sdio->irq_handler = NULL;
  94}
  95
  96static int b43_sdio_probe(struct sdio_func *func,
  97                                    const struct sdio_device_id *id)
  98{
  99        struct b43_sdio *sdio;
 100        struct sdio_func_tuple *tuple;
 101        u16 vendor = 0, device = 0;
 102        int error;
 103
 104        /* Look for the card chip identifier. */
 105        tuple = func->tuples;
 106        while (tuple) {
 107                switch (tuple->code) {
 108                case 0x80:
 109                        switch (tuple->data[0]) {
 110                        case HNBU_CHIPID:
 111                                if (tuple->size != 5)
 112                                        break;
 113                                vendor = tuple->data[1] | (tuple->data[2]<<8);
 114                                device = tuple->data[3] | (tuple->data[4]<<8);
 115                                dev_info(&func->dev, "Chip ID %04x:%04x\n",
 116                                         vendor, device);
 117                                break;
 118                        default:
 119                                break;
 120                        }
 121                        break;
 122                default:
 123                        break;
 124                }
 125                tuple = tuple->next;
 126        }
 127        if (!vendor || !device) {
 128                error = -ENODEV;
 129                goto out;
 130        }
 131
 132        sdio_claim_host(func);
 133        error = sdio_set_block_size(func, B43_SDIO_BLOCK_SIZE);
 134        if (error) {
 135                dev_err(&func->dev, "failed to set block size to %u bytes,"
 136                        " error %d\n", B43_SDIO_BLOCK_SIZE, error);
 137                goto err_release_host;
 138        }
 139        error = sdio_enable_func(func);
 140        if (error) {
 141                dev_err(&func->dev, "failed to enable func, error %d\n", error);
 142                goto err_release_host;
 143        }
 144        sdio_release_host(func);
 145
 146        sdio = kzalloc(sizeof(*sdio), GFP_KERNEL);
 147        if (!sdio) {
 148                error = -ENOMEM;
 149                dev_err(&func->dev, "failed to allocate ssb bus\n");
 150                goto err_disable_func;
 151        }
 152        error = ssb_bus_sdiobus_register(&sdio->ssb, func,
 153                                         b43_sdio_get_quirks(vendor, device));
 154        if (error) {
 155                dev_err(&func->dev, "failed to register ssb sdio bus,"
 156                        " error %d\n", error);
 157                goto err_free_ssb;
 158        }
 159        sdio_set_drvdata(func, sdio);
 160
 161        return 0;
 162
 163err_free_ssb:
 164        kfree(sdio);
 165err_disable_func:
 166        sdio_claim_host(func);
 167        sdio_disable_func(func);
 168err_release_host:
 169        sdio_release_host(func);
 170out:
 171        return error;
 172}
 173
 174static void b43_sdio_remove(struct sdio_func *func)
 175{
 176        struct b43_sdio *sdio = sdio_get_drvdata(func);
 177
 178        ssb_bus_unregister(&sdio->ssb);
 179        sdio_claim_host(func);
 180        sdio_disable_func(func);
 181        sdio_release_host(func);
 182        kfree(sdio);
 183        sdio_set_drvdata(func, NULL);
 184}
 185
 186static const struct sdio_device_id b43_sdio_ids[] = {
 187        { SDIO_DEVICE(0x02d0, 0x044b) }, /* Nintendo Wii WLAN daughter card */
 188        { SDIO_DEVICE(0x0092, 0x0004) }, /* C-guys, Inc. EW-CG1102GC */
 189        { },
 190};
 191
 192static struct sdio_driver b43_sdio_driver = {
 193        .name           = "b43-sdio",
 194        .id_table       = b43_sdio_ids,
 195        .probe          = b43_sdio_probe,
 196        .remove         = b43_sdio_remove,
 197};
 198
 199int b43_sdio_init(void)
 200{
 201        return sdio_register_driver(&b43_sdio_driver);
 202}
 203
 204void b43_sdio_exit(void)
 205{
 206        sdio_unregister_driver(&b43_sdio_driver);
 207}
 208