aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
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
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')
-rw-r--r--drivers/net/wireless/b43/Kconfig21
-rw-r--r--drivers/net/wireless/b43/Makefile1
-rw-r--r--drivers/net/wireless/b43/main.c76
-rw-r--r--drivers/net/wireless/b43/sdio.c197
-rw-r--r--drivers/net/wireless/b43/sdio.h45
5 files changed, 324 insertions, 16 deletions
diff --git a/drivers/net/wireless/b43/Kconfig b/drivers/net/wireless/b43/Kconfig
index 83e38134acc..4fc2ce429c7 100644
--- a/drivers/net/wireless/b43/Kconfig
+++ b/drivers/net/wireless/b43/Kconfig
@@ -61,11 +61,28 @@ config B43_PCMCIA
61 61
62 If unsure, say N. 62 If unsure, say N.
63 63
64config B43_SDIO
65 bool "Broadcom 43xx SDIO device support (EXPERIMENTAL)"
66 depends on B43 && SSB_SDIOHOST_POSSIBLE && EXPERIMENTAL && BROKEN
67 select SSB_SDIOHOST
68 ---help---
69 Broadcom 43xx device support for Soft-MAC SDIO devices.
70
71 With this config option you can drive Soft-MAC b43 cards with a
72 Secure Digital I/O interface.
73 This includes the WLAN daughter card found on the Nintendo Wii
74 video game console.
75 Note that this does not support Broadcom 43xx Full-MAC devices.
76
77 It's safe to select Y here, even if you don't have a B43 SDIO device.
78
79 If unsure, say N.
80
64# Data transfers to the device via PIO 81# Data transfers to the device via PIO
65# This is only needed on PCMCIA devices. All others can do DMA properly. 82# This is only needed on PCMCIA and SDIO devices. All others can do DMA properly.
66config B43_PIO 83config B43_PIO
67 bool 84 bool
68 depends on B43 && (B43_PCMCIA || B43_FORCE_PIO) 85 depends on B43 && (B43_SDIO || B43_PCMCIA || B43_FORCE_PIO)
69 select SSB_BLOCKIO 86 select SSB_BLOCKIO
70 default y 87 default y
71 88
diff --git a/drivers/net/wireless/b43/Makefile b/drivers/net/wireless/b43/Makefile
index da379f4b0c3..84772a2542d 100644
--- a/drivers/net/wireless/b43/Makefile
+++ b/drivers/net/wireless/b43/Makefile
@@ -16,6 +16,7 @@ b43-$(CONFIG_B43_PIO) += pio.o
16b43-y += rfkill.o 16b43-y += rfkill.o
17b43-$(CONFIG_B43_LEDS) += leds.o 17b43-$(CONFIG_B43_LEDS) += leds.o
18b43-$(CONFIG_B43_PCMCIA) += pcmcia.o 18b43-$(CONFIG_B43_PCMCIA) += pcmcia.o
19b43-$(CONFIG_B43_SDIO) += sdio.o
19b43-$(CONFIG_B43_DEBUG) += debugfs.o 20b43-$(CONFIG_B43_DEBUG) += debugfs.o
20 21
21obj-$(CONFIG_B43) += b43.o 22obj-$(CONFIG_B43) += b43.o
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index 2984a915f8b..950a838757c 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -8,6 +8,9 @@
8 Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org> 8 Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org>
9 Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch> 9 Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
10 10
11 SDIO support
12 Copyright (c) 2009 Albert Herranz <albert_herranz@yahoo.es>
13
11 Some parts of the code in this file are derived from the ipw2200 14 Some parts of the code in this file are derived from the ipw2200
12 driver Copyright(c) 2003 - 2004 Intel Corporation. 15 driver Copyright(c) 2003 - 2004 Intel Corporation.
13 16
@@ -53,6 +56,8 @@
53#include "xmit.h" 56#include "xmit.h"
54#include "lo.h" 57#include "lo.h"
55#include "pcmcia.h" 58#include "pcmcia.h"
59#include "sdio.h"
60#include <linux/mmc/sdio_func.h>
56 61
57MODULE_DESCRIPTION("Broadcom B43 wireless driver"); 62MODULE_DESCRIPTION("Broadcom B43 wireless driver");
58MODULE_AUTHOR("Martin Langer"); 63MODULE_AUTHOR("Martin Langer");
@@ -1587,7 +1592,7 @@ static void b43_beacon_update_trigger_work(struct work_struct *work)
1587 mutex_lock(&wl->mutex); 1592 mutex_lock(&wl->mutex);
1588 dev = wl->current_dev; 1593 dev = wl->current_dev;
1589 if (likely(dev && (b43_status(dev) >= B43_STAT_INITIALIZED))) { 1594 if (likely(dev && (b43_status(dev) >= B43_STAT_INITIALIZED))) {
1590 if (0 /*FIXME dev->dev->bus->bustype == SSB_BUSTYPE_SDIO*/) { 1595 if (dev->dev->bus->bustype == SSB_BUSTYPE_SDIO) {
1591 /* wl->mutex is enough. */ 1596 /* wl->mutex is enough. */
1592 b43_do_beacon_update_trigger_work(dev); 1597 b43_do_beacon_update_trigger_work(dev);
1593 mmiowb(); 1598 mmiowb();
@@ -1905,6 +1910,27 @@ static irqreturn_t b43_interrupt_handler(int irq, void *dev_id)
1905 return ret; 1910 return ret;
1906} 1911}
1907 1912
1913/* SDIO interrupt handler. This runs in process context. */
1914static void b43_sdio_interrupt_handler(struct b43_wldev *dev)
1915{
1916 struct b43_wl *wl = dev->wl;
1917 struct sdio_func *func = dev->dev->bus->host_sdio;
1918 irqreturn_t ret;
1919
1920 if (unlikely(b43_status(dev) < B43_STAT_STARTED))
1921 return;
1922
1923 mutex_lock(&wl->mutex);
1924 sdio_release_host(func);
1925
1926 ret = b43_do_interrupt(dev);
1927 if (ret == IRQ_WAKE_THREAD)
1928 b43_do_interrupt_thread(dev);
1929
1930 sdio_claim_host(func);
1931 mutex_unlock(&wl->mutex);
1932}
1933
1908void b43_do_release_fw(struct b43_firmware_file *fw) 1934void b43_do_release_fw(struct b43_firmware_file *fw)
1909{ 1935{
1910 release_firmware(fw->data); 1936 release_firmware(fw->data);
@@ -3824,7 +3850,7 @@ redo:
3824 3850
3825 /* Disable interrupts on the device. */ 3851 /* Disable interrupts on the device. */
3826 b43_set_status(dev, B43_STAT_INITIALIZED); 3852 b43_set_status(dev, B43_STAT_INITIALIZED);
3827 if (0 /*FIXME dev->dev->bus->bustype == SSB_BUSTYPE_SDIO*/) { 3853 if (dev->dev->bus->bustype == SSB_BUSTYPE_SDIO) {
3828 /* wl->mutex is locked. That is enough. */ 3854 /* wl->mutex is locked. That is enough. */
3829 b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, 0); 3855 b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, 0);
3830 b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); /* Flush */ 3856 b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); /* Flush */
@@ -3854,7 +3880,10 @@ redo:
3854 dev_kfree_skb(skb_dequeue(&wl->tx_queue)); 3880 dev_kfree_skb(skb_dequeue(&wl->tx_queue));
3855 3881
3856 b43_mac_suspend(dev); 3882 b43_mac_suspend(dev);
3857 free_irq(dev->dev->irq, dev); 3883 if (dev->dev->bus->bustype == SSB_BUSTYPE_SDIO)
3884 b43_sdio_free_irq(dev);
3885 else
3886 free_irq(dev->dev->irq, dev);
3858 b43_leds_exit(dev); 3887 b43_leds_exit(dev);
3859 b43dbg(wl, "Wireless interface stopped\n"); 3888 b43dbg(wl, "Wireless interface stopped\n");
3860 3889
@@ -3869,12 +3898,20 @@ static int b43_wireless_core_start(struct b43_wldev *dev)
3869 B43_WARN_ON(b43_status(dev) != B43_STAT_INITIALIZED); 3898 B43_WARN_ON(b43_status(dev) != B43_STAT_INITIALIZED);
3870 3899
3871 drain_txstatus_queue(dev); 3900 drain_txstatus_queue(dev);
3872 err = request_threaded_irq(dev->dev->irq, b43_interrupt_handler, 3901 if (dev->dev->bus->bustype == SSB_BUSTYPE_SDIO) {
3873 b43_interrupt_thread_handler, 3902 err = b43_sdio_request_irq(dev, b43_sdio_interrupt_handler);
3874 IRQF_SHARED, KBUILD_MODNAME, dev); 3903 if (err) {
3875 if (err) { 3904 b43err(dev->wl, "Cannot request SDIO IRQ\n");
3876 b43err(dev->wl, "Cannot request IRQ-%d\n", dev->dev->irq); 3905 goto out;
3877 goto out; 3906 }
3907 } else {
3908 err = request_threaded_irq(dev->dev->irq, b43_interrupt_handler,
3909 b43_interrupt_thread_handler,
3910 IRQF_SHARED, KBUILD_MODNAME, dev);
3911 if (err) {
3912 b43err(dev->wl, "Cannot request IRQ-%d\n", dev->dev->irq);
3913 goto out;
3914 }
3878 } 3915 }
3879 3916
3880 /* We are ready to run. */ 3917 /* We are ready to run. */
@@ -4266,7 +4303,9 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
4266 /* Maximum Contention Window */ 4303 /* Maximum Contention Window */
4267 b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_MAXCONT, 0x3FF); 4304 b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_MAXCONT, 0x3FF);
4268 4305
4269 if ((dev->dev->bus->bustype == SSB_BUSTYPE_PCMCIA) || B43_FORCE_PIO) { 4306 if ((dev->dev->bus->bustype == SSB_BUSTYPE_PCMCIA) ||
4307 (dev->dev->bus->bustype == SSB_BUSTYPE_SDIO) ||
4308 B43_FORCE_PIO) {
4270 dev->__using_pio_transfers = 1; 4309 dev->__using_pio_transfers = 1;
4271 err = b43_pio_init(dev); 4310 err = b43_pio_init(dev);
4272 } else { 4311 } else {
@@ -4942,7 +4981,7 @@ static struct ssb_driver b43_ssb_driver = {
4942static void b43_print_driverinfo(void) 4981static void b43_print_driverinfo(void)
4943{ 4982{
4944 const char *feat_pci = "", *feat_pcmcia = "", *feat_nphy = "", 4983 const char *feat_pci = "", *feat_pcmcia = "", *feat_nphy = "",
4945 *feat_leds = ""; 4984 *feat_leds = "", *feat_sdio = "";
4946 4985
4947#ifdef CONFIG_B43_PCI_AUTOSELECT 4986#ifdef CONFIG_B43_PCI_AUTOSELECT
4948 feat_pci = "P"; 4987 feat_pci = "P";
@@ -4956,11 +4995,14 @@ static void b43_print_driverinfo(void)
4956#ifdef CONFIG_B43_LEDS 4995#ifdef CONFIG_B43_LEDS
4957 feat_leds = "L"; 4996 feat_leds = "L";
4958#endif 4997#endif
4998#ifdef CONFIG_B43_SDIO
4999 feat_sdio = "S";
5000#endif
4959 printk(KERN_INFO "Broadcom 43xx driver loaded " 5001 printk(KERN_INFO "Broadcom 43xx driver loaded "
4960 "[ Features: %s%s%s%s, Firmware-ID: " 5002 "[ Features: %s%s%s%s%s, Firmware-ID: "
4961 B43_SUPPORTED_FIRMWARE_ID " ]\n", 5003 B43_SUPPORTED_FIRMWARE_ID " ]\n",
4962 feat_pci, feat_pcmcia, feat_nphy, 5004 feat_pci, feat_pcmcia, feat_nphy,
4963 feat_leds); 5005 feat_leds, feat_sdio);
4964} 5006}
4965 5007
4966static int __init b43_init(void) 5008static int __init b43_init(void)
@@ -4971,13 +5013,18 @@ static int __init b43_init(void)
4971 err = b43_pcmcia_init(); 5013 err = b43_pcmcia_init();
4972 if (err) 5014 if (err)
4973 goto err_dfs_exit; 5015 goto err_dfs_exit;
4974 err = ssb_driver_register(&b43_ssb_driver); 5016 err = b43_sdio_init();
4975 if (err) 5017 if (err)
4976 goto err_pcmcia_exit; 5018 goto err_pcmcia_exit;
5019 err = ssb_driver_register(&b43_ssb_driver);
5020 if (err)
5021 goto err_sdio_exit;
4977 b43_print_driverinfo(); 5022 b43_print_driverinfo();
4978 5023
4979 return err; 5024 return err;
4980 5025
5026err_sdio_exit:
5027 b43_sdio_exit();
4981err_pcmcia_exit: 5028err_pcmcia_exit:
4982 b43_pcmcia_exit(); 5029 b43_pcmcia_exit();
4983err_dfs_exit: 5030err_dfs_exit:
@@ -4988,6 +5035,7 @@ err_dfs_exit:
4988static void __exit b43_exit(void) 5035static void __exit b43_exit(void)
4989{ 5036{
4990 ssb_driver_unregister(&b43_ssb_driver); 5037 ssb_driver_unregister(&b43_ssb_driver);
5038 b43_sdio_exit();
4991 b43_pcmcia_exit(); 5039 b43_pcmcia_exit();
4992 b43_debugfs_exit(); 5040 b43_debugfs_exit();
4993} 5041}
diff --git a/drivers/net/wireless/b43/sdio.c b/drivers/net/wireless/b43/sdio.c
new file mode 100644
index 00000000000..2d337f1a60b
--- /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}
diff --git a/drivers/net/wireless/b43/sdio.h b/drivers/net/wireless/b43/sdio.h
new file mode 100644
index 00000000000..fb633094403
--- /dev/null
+++ b/drivers/net/wireless/b43/sdio.h
@@ -0,0 +1,45 @@
1#ifndef B43_SDIO_H_
2#define B43_SDIO_H_
3
4#include <linux/ssb/ssb.h>
5
6struct b43_wldev;
7
8
9#ifdef CONFIG_B43_SDIO
10
11struct b43_sdio {
12 struct ssb_bus ssb;
13 void *irq_handler_opaque;
14 void (*irq_handler)(struct b43_wldev *dev);
15};
16
17int b43_sdio_request_irq(struct b43_wldev *dev,
18 void (*handler)(struct b43_wldev *dev));
19void b43_sdio_free_irq(struct b43_wldev *dev);
20
21int b43_sdio_init(void);
22void b43_sdio_exit(void);
23
24
25#else /* CONFIG_B43_SDIO */
26
27
28int b43_sdio_request_irq(struct b43_wldev *dev,
29 void (*handler)(struct b43_wldev *dev))
30{
31 return -ENODEV;
32}
33void b43_sdio_free_irq(struct b43_wldev *dev)
34{
35}
36static inline int b43_sdio_init(void)
37{
38 return 0;
39}
40static inline void b43_sdio_exit(void)
41{
42}
43
44#endif /* CONFIG_B43_SDIO */
45#endif /* B43_SDIO_H_ */