diff options
author | David Kilroy <kilroyd@googlemail.com> | 2008-10-31 09:35:21 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-11-10 15:17:42 -0500 |
commit | b2e53b338b7b4608372d070bb477f3bae3971e5a (patch) | |
tree | 1d2bc35201029e8cd0b8007c5ebc0b07fd1a03ec /drivers/net/wireless/orinoco_plx.c | |
parent | 5166ccd220f187b2e9edfc5f01eb49f4a0ebf586 (diff) |
orinoco: Move sources to a subdirectory
Keeping all the orinoco drivers in a common directory will make
maintenance easier.
Signed-off by: David Kilroy <kilroyd@googlemail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/orinoco_plx.c')
-rw-r--r-- | drivers/net/wireless/orinoco_plx.c | 371 |
1 files changed, 0 insertions, 371 deletions
diff --git a/drivers/net/wireless/orinoco_plx.c b/drivers/net/wireless/orinoco_plx.c deleted file mode 100644 index ef761857bb38..000000000000 --- a/drivers/net/wireless/orinoco_plx.c +++ /dev/null | |||
@@ -1,371 +0,0 @@ | |||
1 | /* orinoco_plx.c | ||
2 | * | ||
3 | * Driver for Prism II devices which would usually be driven by orinoco_cs, | ||
4 | * but are connected to the PCI bus by a PLX9052. | ||
5 | * | ||
6 | * Current maintainers are: | ||
7 | * Pavel Roskin <proski AT gnu.org> | ||
8 | * and David Gibson <hermes AT gibson.dropbear.id.au> | ||
9 | * | ||
10 | * (C) Copyright David Gibson, IBM Corp. 2001-2003. | ||
11 | * Copyright (C) 2001 Daniel Barlow | ||
12 | * | ||
13 | * The contents of this file are subject to the Mozilla Public License | ||
14 | * Version 1.1 (the "License"); you may not use this file except in | ||
15 | * compliance with the License. You may obtain a copy of the License | ||
16 | * at http://www.mozilla.org/MPL/ | ||
17 | * | ||
18 | * Software distributed under the License is distributed on an "AS IS" | ||
19 | * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See | ||
20 | * the License for the specific language governing rights and | ||
21 | * limitations under the License. | ||
22 | * | ||
23 | * Alternatively, the contents of this file may be used under the | ||
24 | * terms of the GNU General Public License version 2 (the "GPL"), in | ||
25 | * which case the provisions of the GPL are applicable instead of the | ||
26 | * above. If you wish to allow the use of your version of this file | ||
27 | * only under the terms of the GPL and not to allow others to use your | ||
28 | * version of this file under the MPL, indicate your decision by | ||
29 | * deleting the provisions above and replace them with the notice and | ||
30 | * other provisions required by the GPL. If you do not delete the | ||
31 | * provisions above, a recipient may use your version of this file | ||
32 | * under either the MPL or the GPL. | ||
33 | * | ||
34 | * Here's the general details on how the PLX9052 adapter works: | ||
35 | * | ||
36 | * - Two PCI I/O address spaces, one 0x80 long which contains the | ||
37 | * PLX9052 registers, and one that's 0x40 long mapped to the PCMCIA | ||
38 | * slot I/O address space. | ||
39 | * | ||
40 | * - One PCI memory address space, mapped to the PCMCIA attribute space | ||
41 | * (containing the CIS). | ||
42 | * | ||
43 | * Using the later, you can read through the CIS data to make sure the | ||
44 | * card is compatible with the driver. Keep in mind that the PCMCIA | ||
45 | * spec specifies the CIS as the lower 8 bits of each word read from | ||
46 | * the CIS, so to read the bytes of the CIS, read every other byte | ||
47 | * (0,2,4,...). Passing that test, you need to enable the I/O address | ||
48 | * space on the PCMCIA card via the PCMCIA COR register. This is the | ||
49 | * first byte following the CIS. In my case (which may not have any | ||
50 | * relation to what's on the PRISM2 cards), COR was at offset 0x800 | ||
51 | * within the PCI memory space. Write 0x41 to the COR register to | ||
52 | * enable I/O mode and to select level triggered interrupts. To | ||
53 | * confirm you actually succeeded, read the COR register back and make | ||
54 | * sure it actually got set to 0x41, in case you have an unexpected | ||
55 | * card inserted. | ||
56 | * | ||
57 | * Following that, you can treat the second PCI I/O address space (the | ||
58 | * one that's not 0x80 in length) as the PCMCIA I/O space. | ||
59 | * | ||
60 | * Note that in the Eumitcom's source for their drivers, they register | ||
61 | * the interrupt as edge triggered when registering it with the | ||
62 | * Windows kernel. I don't recall how to register edge triggered on | ||
63 | * Linux (if it can be done at all). But in some experimentation, I | ||
64 | * don't see much operational difference between using either | ||
65 | * interrupt mode. Don't mess with the interrupt mode in the COR | ||
66 | * register though, as the PLX9052 wants level triggers with the way | ||
67 | * the serial EEPROM configures it on the WL11000. | ||
68 | * | ||
69 | * There's some other little quirks related to timing that I bumped | ||
70 | * into, but I don't recall right now. Also, there's two variants of | ||
71 | * the WL11000 I've seen, revision A1 and T2. These seem to differ | ||
72 | * slightly in the timings configured in the wait-state generator in | ||
73 | * the PLX9052. There have also been some comments from Eumitcom that | ||
74 | * cards shouldn't be hot swapped, apparently due to risk of cooking | ||
75 | * the PLX9052. I'm unsure why they believe this, as I can't see | ||
76 | * anything in the design that would really cause a problem, except | ||
77 | * for crashing drivers not written to expect it. And having developed | ||
78 | * drivers for the WL11000, I'd say it's quite tricky to write code | ||
79 | * that will successfully deal with a hot unplug. Very odd things | ||
80 | * happen on the I/O side of things. But anyway, be warned. Despite | ||
81 | * that, I've hot-swapped a number of times during debugging and | ||
82 | * driver development for various reasons (stuck WAIT# line after the | ||
83 | * radio card's firmware locks up). | ||
84 | */ | ||
85 | |||
86 | #define DRIVER_NAME "orinoco_plx" | ||
87 | #define PFX DRIVER_NAME ": " | ||
88 | |||
89 | #include <linux/module.h> | ||
90 | #include <linux/kernel.h> | ||
91 | #include <linux/init.h> | ||
92 | #include <linux/delay.h> | ||
93 | #include <linux/pci.h> | ||
94 | #include <pcmcia/cisreg.h> | ||
95 | |||
96 | #include "orinoco.h" | ||
97 | #include "orinoco_pci.h" | ||
98 | |||
99 | #define COR_OFFSET (0x3e0) /* COR attribute offset of Prism2 PC card */ | ||
100 | #define COR_VALUE (COR_LEVEL_REQ | COR_FUNC_ENA) /* Enable PC card with interrupt in level trigger */ | ||
101 | #define COR_RESET (0x80) /* reset bit in the COR register */ | ||
102 | #define PLX_RESET_TIME (500) /* milliseconds */ | ||
103 | |||
104 | #define PLX_INTCSR 0x4c /* Interrupt Control & Status Register */ | ||
105 | #define PLX_INTCSR_INTEN (1<<6) /* Interrupt Enable bit */ | ||
106 | |||
107 | /* | ||
108 | * Do a soft reset of the card using the Configuration Option Register | ||
109 | */ | ||
110 | static int orinoco_plx_cor_reset(struct orinoco_private *priv) | ||
111 | { | ||
112 | hermes_t *hw = &priv->hw; | ||
113 | struct orinoco_pci_card *card = priv->card; | ||
114 | unsigned long timeout; | ||
115 | u16 reg; | ||
116 | |||
117 | iowrite8(COR_VALUE | COR_RESET, card->attr_io + COR_OFFSET); | ||
118 | mdelay(1); | ||
119 | |||
120 | iowrite8(COR_VALUE, card->attr_io + COR_OFFSET); | ||
121 | mdelay(1); | ||
122 | |||
123 | /* Just in case, wait more until the card is no longer busy */ | ||
124 | timeout = jiffies + (PLX_RESET_TIME * HZ / 1000); | ||
125 | reg = hermes_read_regn(hw, CMD); | ||
126 | while (time_before(jiffies, timeout) && (reg & HERMES_CMD_BUSY)) { | ||
127 | mdelay(1); | ||
128 | reg = hermes_read_regn(hw, CMD); | ||
129 | } | ||
130 | |||
131 | /* Still busy? */ | ||
132 | if (reg & HERMES_CMD_BUSY) { | ||
133 | printk(KERN_ERR PFX "Busy timeout\n"); | ||
134 | return -ETIMEDOUT; | ||
135 | } | ||
136 | |||
137 | return 0; | ||
138 | } | ||
139 | |||
140 | static int orinoco_plx_hw_init(struct orinoco_pci_card *card) | ||
141 | { | ||
142 | int i; | ||
143 | u32 csr_reg; | ||
144 | static const u8 cis_magic[] = { | ||
145 | 0x01, 0x03, 0x00, 0x00, 0xff, 0x17, 0x04, 0x67 | ||
146 | }; | ||
147 | |||
148 | printk(KERN_DEBUG PFX "CIS: "); | ||
149 | for (i = 0; i < 16; i++) { | ||
150 | printk("%02X:", ioread8(card->attr_io + (i << 1))); | ||
151 | } | ||
152 | printk("\n"); | ||
153 | |||
154 | /* Verify whether a supported PC card is present */ | ||
155 | /* FIXME: we probably need to be smarted about this */ | ||
156 | for (i = 0; i < sizeof(cis_magic); i++) { | ||
157 | if (cis_magic[i] != ioread8(card->attr_io + (i << 1))) { | ||
158 | printk(KERN_ERR PFX "The CIS value of Prism2 PC " | ||
159 | "card is unexpected\n"); | ||
160 | return -ENODEV; | ||
161 | } | ||
162 | } | ||
163 | |||
164 | /* bjoern: We need to tell the card to enable interrupts, in | ||
165 | case the serial eprom didn't do this already. See the | ||
166 | PLX9052 data book, p8-1 and 8-24 for reference. */ | ||
167 | csr_reg = ioread32(card->bridge_io + PLX_INTCSR); | ||
168 | if (!(csr_reg & PLX_INTCSR_INTEN)) { | ||
169 | csr_reg |= PLX_INTCSR_INTEN; | ||
170 | iowrite32(csr_reg, card->bridge_io + PLX_INTCSR); | ||
171 | csr_reg = ioread32(card->bridge_io + PLX_INTCSR); | ||
172 | if (!(csr_reg & PLX_INTCSR_INTEN)) { | ||
173 | printk(KERN_ERR PFX "Cannot enable interrupts\n"); | ||
174 | return -EIO; | ||
175 | } | ||
176 | } | ||
177 | |||
178 | return 0; | ||
179 | } | ||
180 | |||
181 | static int orinoco_plx_init_one(struct pci_dev *pdev, | ||
182 | const struct pci_device_id *ent) | ||
183 | { | ||
184 | int err; | ||
185 | struct orinoco_private *priv; | ||
186 | struct orinoco_pci_card *card; | ||
187 | struct net_device *dev; | ||
188 | void __iomem *hermes_io, *attr_io, *bridge_io; | ||
189 | |||
190 | err = pci_enable_device(pdev); | ||
191 | if (err) { | ||
192 | printk(KERN_ERR PFX "Cannot enable PCI device\n"); | ||
193 | return err; | ||
194 | } | ||
195 | |||
196 | err = pci_request_regions(pdev, DRIVER_NAME); | ||
197 | if (err) { | ||
198 | printk(KERN_ERR PFX "Cannot obtain PCI resources\n"); | ||
199 | goto fail_resources; | ||
200 | } | ||
201 | |||
202 | bridge_io = pci_iomap(pdev, 1, 0); | ||
203 | if (!bridge_io) { | ||
204 | printk(KERN_ERR PFX "Cannot map bridge registers\n"); | ||
205 | err = -EIO; | ||
206 | goto fail_map_bridge; | ||
207 | } | ||
208 | |||
209 | attr_io = pci_iomap(pdev, 2, 0); | ||
210 | if (!attr_io) { | ||
211 | printk(KERN_ERR PFX "Cannot map PCMCIA attributes\n"); | ||
212 | err = -EIO; | ||
213 | goto fail_map_attr; | ||
214 | } | ||
215 | |||
216 | hermes_io = pci_iomap(pdev, 3, 0); | ||
217 | if (!hermes_io) { | ||
218 | printk(KERN_ERR PFX "Cannot map chipset registers\n"); | ||
219 | err = -EIO; | ||
220 | goto fail_map_hermes; | ||
221 | } | ||
222 | |||
223 | /* Allocate network device */ | ||
224 | dev = alloc_orinocodev(sizeof(*card), &pdev->dev, | ||
225 | orinoco_plx_cor_reset, NULL); | ||
226 | if (!dev) { | ||
227 | printk(KERN_ERR PFX "Cannot allocate network device\n"); | ||
228 | err = -ENOMEM; | ||
229 | goto fail_alloc; | ||
230 | } | ||
231 | |||
232 | priv = netdev_priv(dev); | ||
233 | card = priv->card; | ||
234 | card->bridge_io = bridge_io; | ||
235 | card->attr_io = attr_io; | ||
236 | SET_NETDEV_DEV(dev, &pdev->dev); | ||
237 | |||
238 | hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING); | ||
239 | |||
240 | err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED, | ||
241 | dev->name, dev); | ||
242 | if (err) { | ||
243 | printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq); | ||
244 | err = -EBUSY; | ||
245 | goto fail_irq; | ||
246 | } | ||
247 | |||
248 | err = orinoco_plx_hw_init(card); | ||
249 | if (err) { | ||
250 | printk(KERN_ERR PFX "Hardware initialization failed\n"); | ||
251 | goto fail; | ||
252 | } | ||
253 | |||
254 | err = orinoco_plx_cor_reset(priv); | ||
255 | if (err) { | ||
256 | printk(KERN_ERR PFX "Initial reset failed\n"); | ||
257 | goto fail; | ||
258 | } | ||
259 | |||
260 | err = register_netdev(dev); | ||
261 | if (err) { | ||
262 | printk(KERN_ERR PFX "Cannot register network device\n"); | ||
263 | goto fail; | ||
264 | } | ||
265 | |||
266 | pci_set_drvdata(pdev, dev); | ||
267 | printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s\n", dev->name, | ||
268 | pci_name(pdev)); | ||
269 | |||
270 | return 0; | ||
271 | |||
272 | fail: | ||
273 | free_irq(pdev->irq, dev); | ||
274 | |||
275 | fail_irq: | ||
276 | pci_set_drvdata(pdev, NULL); | ||
277 | free_orinocodev(dev); | ||
278 | |||
279 | fail_alloc: | ||
280 | pci_iounmap(pdev, hermes_io); | ||
281 | |||
282 | fail_map_hermes: | ||
283 | pci_iounmap(pdev, attr_io); | ||
284 | |||
285 | fail_map_attr: | ||
286 | pci_iounmap(pdev, bridge_io); | ||
287 | |||
288 | fail_map_bridge: | ||
289 | pci_release_regions(pdev); | ||
290 | |||
291 | fail_resources: | ||
292 | pci_disable_device(pdev); | ||
293 | |||
294 | return err; | ||
295 | } | ||
296 | |||
297 | static void __devexit orinoco_plx_remove_one(struct pci_dev *pdev) | ||
298 | { | ||
299 | struct net_device *dev = pci_get_drvdata(pdev); | ||
300 | struct orinoco_private *priv = netdev_priv(dev); | ||
301 | struct orinoco_pci_card *card = priv->card; | ||
302 | |||
303 | unregister_netdev(dev); | ||
304 | free_irq(pdev->irq, dev); | ||
305 | pci_set_drvdata(pdev, NULL); | ||
306 | free_orinocodev(dev); | ||
307 | pci_iounmap(pdev, priv->hw.iobase); | ||
308 | pci_iounmap(pdev, card->attr_io); | ||
309 | pci_iounmap(pdev, card->bridge_io); | ||
310 | pci_release_regions(pdev); | ||
311 | pci_disable_device(pdev); | ||
312 | } | ||
313 | |||
314 | static struct pci_device_id orinoco_plx_id_table[] = { | ||
315 | {0x111a, 0x1023, PCI_ANY_ID, PCI_ANY_ID,}, /* Siemens SpeedStream SS1023 */ | ||
316 | {0x1385, 0x4100, PCI_ANY_ID, PCI_ANY_ID,}, /* Netgear MA301 */ | ||
317 | {0x15e8, 0x0130, PCI_ANY_ID, PCI_ANY_ID,}, /* Correga - does this work? */ | ||
318 | {0x1638, 0x1100, PCI_ANY_ID, PCI_ANY_ID,}, /* SMC EZConnect SMC2602W, | ||
319 | Eumitcom PCI WL11000, | ||
320 | Addtron AWA-100 */ | ||
321 | {0x16ab, 0x1100, PCI_ANY_ID, PCI_ANY_ID,}, /* Global Sun Tech GL24110P */ | ||
322 | {0x16ab, 0x1101, PCI_ANY_ID, PCI_ANY_ID,}, /* Reported working, but unknown */ | ||
323 | {0x16ab, 0x1102, PCI_ANY_ID, PCI_ANY_ID,}, /* Linksys WDT11 */ | ||
324 | {0x16ec, 0x3685, PCI_ANY_ID, PCI_ANY_ID,}, /* USR 2415 */ | ||
325 | {0xec80, 0xec00, PCI_ANY_ID, PCI_ANY_ID,}, /* Belkin F5D6000 tested by | ||
326 | Brendan W. McAdams <rit AT jacked-in.org> */ | ||
327 | {0x10b7, 0x7770, PCI_ANY_ID, PCI_ANY_ID,}, /* 3Com AirConnect PCI tested by | ||
328 | Damien Persohn <damien AT persohn.net> */ | ||
329 | {0,}, | ||
330 | }; | ||
331 | |||
332 | MODULE_DEVICE_TABLE(pci, orinoco_plx_id_table); | ||
333 | |||
334 | static struct pci_driver orinoco_plx_driver = { | ||
335 | .name = DRIVER_NAME, | ||
336 | .id_table = orinoco_plx_id_table, | ||
337 | .probe = orinoco_plx_init_one, | ||
338 | .remove = __devexit_p(orinoco_plx_remove_one), | ||
339 | .suspend = orinoco_pci_suspend, | ||
340 | .resume = orinoco_pci_resume, | ||
341 | }; | ||
342 | |||
343 | static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION | ||
344 | " (Pavel Roskin <proski@gnu.org>," | ||
345 | " David Gibson <hermes@gibson.dropbear.id.au>," | ||
346 | " Daniel Barlow <dan@telent.net>)"; | ||
347 | MODULE_AUTHOR("Daniel Barlow <dan@telent.net>"); | ||
348 | MODULE_DESCRIPTION("Driver for wireless LAN cards using the PLX9052 PCI bridge"); | ||
349 | MODULE_LICENSE("Dual MPL/GPL"); | ||
350 | |||
351 | static int __init orinoco_plx_init(void) | ||
352 | { | ||
353 | printk(KERN_DEBUG "%s\n", version); | ||
354 | return pci_register_driver(&orinoco_plx_driver); | ||
355 | } | ||
356 | |||
357 | static void __exit orinoco_plx_exit(void) | ||
358 | { | ||
359 | pci_unregister_driver(&orinoco_plx_driver); | ||
360 | } | ||
361 | |||
362 | module_init(orinoco_plx_init); | ||
363 | module_exit(orinoco_plx_exit); | ||
364 | |||
365 | /* | ||
366 | * Local variables: | ||
367 | * c-indent-level: 8 | ||
368 | * c-basic-offset: 8 | ||
369 | * tab-width: 8 | ||
370 | * End: | ||
371 | */ | ||