aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/b43/sdio.c
diff options
context:
space:
mode:
authorAlbert Herranz <albert_herranz@yahoo.es>2009-09-10 13:34:49 -0400
committerJohn W. Linville <linville@tuxdriver.com>2009-09-23 11:35:43 -0400
commit3dbba8e281552da640080f08a0f127d48456669f (patch)
tree111f1db7448c7e3214e02e6d09d7e8f285727188 /drivers/net/wireless/b43/sdio.c
parenta78b3bb2f3ab9afcf78dbcff18fd7bf900c7c27e (diff)
b43: Add Soft-MAC SDIO device support
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. Signed-off-by: Albert Herranz <albert_herranz@yahoo.es> Signed-off-by: Michael Buesch <mb@bu3sch.de> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/b43/sdio.c')
-rw-r--r--drivers/net/wireless/b43/sdio.c197
1 files changed, 197 insertions, 0 deletions
diff --git a/drivers/net/wireless/b43/sdio.c b/drivers/net/wireless/b43/sdio.c
new file mode 100644
index 000000000000..2d337f1a60b2
--- /dev/null
+++ b/drivers/net/wireless/b43/sdio.c
@@ -0,0 +1,197 @@
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 <mb@bu3sch.de>
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/ssb/ssb.h>
20
21#include "sdio.h"
22#include "b43.h"
23
24
25#define HNBU_CHIPID 0x01 /* vendor & device id */
26
27#define B43_SDIO_BLOCK_SIZE 64 /* rx fifo max size in bytes */
28
29
30static const struct b43_sdio_quirk {
31 u16 vendor;
32 u16 device;
33 unsigned int quirks;
34} b43_sdio_quirks[] = {
35 { 0x14E4, 0x4318, SSB_QUIRK_SDIO_READ_AFTER_WRITE32, },
36 { },
37};
38
39
40static unsigned int b43_sdio_get_quirks(u16 vendor, u16 device)
41{
42 const struct b43_sdio_quirk *q;
43
44 for (q = b43_sdio_quirks; q->quirks; q++) {
45 if (vendor == q->vendor && device == q->device)
46 return q->quirks;
47 }
48
49 return 0;
50}
51
52static void b43_sdio_interrupt_dispatcher(struct sdio_func *func)
53{
54 struct b43_sdio *sdio = sdio_get_drvdata(func);
55 struct b43_wldev *dev = sdio->irq_handler_opaque;
56
57 sdio->irq_handler(dev);
58}
59
60int b43_sdio_request_irq(struct b43_wldev *dev,
61 void (*handler)(struct b43_wldev *dev))
62{
63 struct ssb_bus *bus = dev->dev->bus;
64 struct sdio_func *func = bus->host_sdio;
65 struct b43_sdio *sdio = sdio_get_drvdata(func);
66 int err;
67
68 sdio->irq_handler_opaque = dev;
69 sdio->irq_handler = handler;
70 sdio_claim_host(func);
71 err = sdio_claim_irq(func, b43_sdio_interrupt_dispatcher);
72 sdio_release_host(func);
73
74 return err;
75}
76
77void b43_sdio_free_irq(struct b43_wldev *dev)
78{
79 struct ssb_bus *bus = dev->dev->bus;
80 struct sdio_func *func = bus->host_sdio;
81 struct b43_sdio *sdio = sdio_get_drvdata(func);
82
83 sdio_claim_host(func);
84 sdio_release_irq(func);
85 sdio_release_host(func);
86 sdio->irq_handler_opaque = NULL;
87 sdio->irq_handler = NULL;
88}
89
90static int b43_sdio_probe(struct sdio_func *func,
91 const struct sdio_device_id *id)
92{
93 struct b43_sdio *sdio;
94 struct sdio_func_tuple *tuple;
95 u16 vendor = 0, device = 0;
96 int error;
97
98 /* Look for the card chip identifier. */
99 tuple = func->tuples;
100 while (tuple) {
101 switch (tuple->code) {
102 case 0x80:
103 switch (tuple->data[0]) {
104 case HNBU_CHIPID:
105 if (tuple->size != 5)
106 break;
107 vendor = tuple->data[1] | (tuple->data[2]<<8);
108 device = tuple->data[3] | (tuple->data[4]<<8);
109 dev_info(&func->dev, "Chip ID %04x:%04x\n",
110 vendor, device);
111 break;
112 default:
113 break;
114 }
115 break;
116 default:
117 break;
118 }
119 tuple = tuple->next;
120 }
121 if (!vendor || !device) {
122 error = -ENODEV;
123 goto out;
124 }
125
126 sdio_claim_host(func);
127 error = sdio_set_block_size(func, B43_SDIO_BLOCK_SIZE);
128 if (error) {
129 dev_err(&func->dev, "failed to set block size to %u bytes,"
130 " error %d\n", B43_SDIO_BLOCK_SIZE, error);
131 goto err_release_host;
132 }
133 error = sdio_enable_func(func);
134 if (error) {
135 dev_err(&func->dev, "failed to enable func, error %d\n", error);
136 goto err_release_host;
137 }
138 sdio_release_host(func);
139
140 sdio = kzalloc(sizeof(*sdio), GFP_KERNEL);
141 if (!sdio) {
142 error = -ENOMEM;
143 dev_err(&func->dev, "failed to allocate ssb bus\n");
144 goto err_disable_func;
145 }
146 error = ssb_bus_sdiobus_register(&sdio->ssb, func,
147 b43_sdio_get_quirks(vendor, device));
148 if (error) {
149 dev_err(&func->dev, "failed to register ssb sdio bus,"
150 " error %d\n", error);
151 goto err_free_ssb;
152 }
153 sdio_set_drvdata(func, sdio);
154
155 return 0;
156
157err_free_ssb:
158 kfree(sdio);
159err_disable_func:
160 sdio_disable_func(func);
161err_release_host:
162 sdio_release_host(func);
163out:
164 return error;
165}
166
167static void b43_sdio_remove(struct sdio_func *func)
168{
169 struct b43_sdio *sdio = sdio_get_drvdata(func);
170
171 ssb_bus_unregister(&sdio->ssb);
172 sdio_disable_func(func);
173 kfree(sdio);
174 sdio_set_drvdata(func, NULL);
175}
176
177static const struct sdio_device_id b43_sdio_ids[] = {
178 { SDIO_DEVICE(0x02d0, 0x044b) }, /* Nintendo Wii WLAN daughter card */
179 { },
180};
181
182static struct sdio_driver b43_sdio_driver = {
183 .name = "b43-sdio",
184 .id_table = b43_sdio_ids,
185 .probe = b43_sdio_probe,
186 .remove = b43_sdio_remove,
187};
188
189int b43_sdio_init(void)
190{
191 return sdio_register_driver(&b43_sdio_driver);
192}
193
194void b43_sdio_exit(void)
195{
196 sdio_unregister_driver(&b43_sdio_driver);
197}