1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
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)
100#define COR_VALUE (COR_LEVEL_REQ | COR_FUNC_ENA)
101#define COR_RESET (0x80)
102#define PLX_RESET_TIME (500)
103
104#define PLX_INTCSR 0x4c
105#define PLX_INTCSR_INTEN (1 << 6)
106
107
108
109
110static int orinoco_plx_cor_reset(struct orinoco_private *priv)
111{
112 struct hermes *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
124 timeout = jiffies + msecs_to_jiffies(PLX_RESET_TIME);
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
132 if (reg & HERMES_CMD_BUSY) {
133 printk(KERN_ERR PFX "Busy timeout\n");
134 return -ETIMEDOUT;
135 }
136
137 return 0;
138}
139
140static 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 printk("\n");
152
153
154
155 for (i = 0; i < sizeof(cis_magic); i++) {
156 if (cis_magic[i] != ioread8(card->attr_io + (i << 1))) {
157 printk(KERN_ERR PFX "The CIS value of Prism2 PC "
158 "card is unexpected\n");
159 return -ENODEV;
160 }
161 }
162
163
164
165
166 csr_reg = ioread32(card->bridge_io + PLX_INTCSR);
167 if (!(csr_reg & PLX_INTCSR_INTEN)) {
168 csr_reg |= PLX_INTCSR_INTEN;
169 iowrite32(csr_reg, card->bridge_io + PLX_INTCSR);
170 csr_reg = ioread32(card->bridge_io + PLX_INTCSR);
171 if (!(csr_reg & PLX_INTCSR_INTEN)) {
172 printk(KERN_ERR PFX "Cannot enable interrupts\n");
173 return -EIO;
174 }
175 }
176
177 return 0;
178}
179
180static int orinoco_plx_init_one(struct pci_dev *pdev,
181 const struct pci_device_id *ent)
182{
183 int err;
184 struct orinoco_private *priv;
185 struct orinoco_pci_card *card;
186 void __iomem *hermes_io, *attr_io, *bridge_io;
187
188 err = pci_enable_device(pdev);
189 if (err) {
190 printk(KERN_ERR PFX "Cannot enable PCI device\n");
191 return err;
192 }
193
194 err = pci_request_regions(pdev, DRIVER_NAME);
195 if (err) {
196 printk(KERN_ERR PFX "Cannot obtain PCI resources\n");
197 goto fail_resources;
198 }
199
200 bridge_io = pci_iomap(pdev, 1, 0);
201 if (!bridge_io) {
202 printk(KERN_ERR PFX "Cannot map bridge registers\n");
203 err = -EIO;
204 goto fail_map_bridge;
205 }
206
207 attr_io = pci_iomap(pdev, 2, 0);
208 if (!attr_io) {
209 printk(KERN_ERR PFX "Cannot map PCMCIA attributes\n");
210 err = -EIO;
211 goto fail_map_attr;
212 }
213
214 hermes_io = pci_iomap(pdev, 3, 0);
215 if (!hermes_io) {
216 printk(KERN_ERR PFX "Cannot map chipset registers\n");
217 err = -EIO;
218 goto fail_map_hermes;
219 }
220
221
222 priv = alloc_orinocodev(sizeof(*card), &pdev->dev,
223 orinoco_plx_cor_reset, NULL);
224 if (!priv) {
225 printk(KERN_ERR PFX "Cannot allocate network device\n");
226 err = -ENOMEM;
227 goto fail_alloc;
228 }
229
230 card = priv->card;
231 card->bridge_io = bridge_io;
232 card->attr_io = attr_io;
233
234 hermes_struct_init(&priv->hw, hermes_io, HERMES_16BIT_REGSPACING);
235
236 err = request_irq(pdev->irq, orinoco_interrupt, IRQF_SHARED,
237 DRIVER_NAME, priv);
238 if (err) {
239 printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq);
240 err = -EBUSY;
241 goto fail_irq;
242 }
243
244 err = orinoco_plx_hw_init(card);
245 if (err) {
246 printk(KERN_ERR PFX "Hardware initialization failed\n");
247 goto fail;
248 }
249
250 err = orinoco_plx_cor_reset(priv);
251 if (err) {
252 printk(KERN_ERR PFX "Initial reset failed\n");
253 goto fail;
254 }
255
256 err = orinoco_init(priv);
257 if (err) {
258 printk(KERN_ERR PFX "orinoco_init() failed\n");
259 goto fail;
260 }
261
262 err = orinoco_if_add(priv, 0, 0, NULL);
263 if (err) {
264 printk(KERN_ERR PFX "orinoco_if_add() failed\n");
265 goto fail_wiphy;
266 }
267
268 pci_set_drvdata(pdev, priv);
269
270 return 0;
271
272 fail_wiphy:
273 wiphy_unregister(priv_to_wiphy(priv));
274 fail:
275 free_irq(pdev->irq, priv);
276
277 fail_irq:
278 free_orinocodev(priv);
279
280 fail_alloc:
281 pci_iounmap(pdev, hermes_io);
282
283 fail_map_hermes:
284 pci_iounmap(pdev, attr_io);
285
286 fail_map_attr:
287 pci_iounmap(pdev, bridge_io);
288
289 fail_map_bridge:
290 pci_release_regions(pdev);
291
292 fail_resources:
293 pci_disable_device(pdev);
294
295 return err;
296}
297
298static void orinoco_plx_remove_one(struct pci_dev *pdev)
299{
300 struct orinoco_private *priv = pci_get_drvdata(pdev);
301 struct orinoco_pci_card *card = priv->card;
302
303 orinoco_if_del(priv);
304 wiphy_unregister(priv_to_wiphy(priv));
305 free_irq(pdev->irq, priv);
306 free_orinocodev(priv);
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
314static const struct pci_device_id orinoco_plx_id_table[] = {
315 {0x111a, 0x1023, PCI_ANY_ID, PCI_ANY_ID,},
316 {0x1385, 0x4100, PCI_ANY_ID, PCI_ANY_ID,},
317 {0x15e8, 0x0130, PCI_ANY_ID, PCI_ANY_ID,},
318 {0x1638, 0x1100, PCI_ANY_ID, PCI_ANY_ID,},
319
320
321 {0x16ab, 0x1100, PCI_ANY_ID, PCI_ANY_ID,},
322 {0x16ab, 0x1101, PCI_ANY_ID, PCI_ANY_ID,},
323 {0x16ab, 0x1102, PCI_ANY_ID, PCI_ANY_ID,},
324 {0x16ec, 0x3685, PCI_ANY_ID, PCI_ANY_ID,},
325 {0xec80, 0xec00, PCI_ANY_ID, PCI_ANY_ID,},
326
327 {0x10b7, 0x7770, PCI_ANY_ID, PCI_ANY_ID,},
328
329 {0,},
330};
331
332MODULE_DEVICE_TABLE(pci, orinoco_plx_id_table);
333
334static 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 = orinoco_plx_remove_one,
339 .suspend = orinoco_pci_suspend,
340 .resume = orinoco_pci_resume,
341};
342
343static 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>)";
347MODULE_AUTHOR("Daniel Barlow <dan@telent.net>");
348MODULE_DESCRIPTION("Driver for wireless LAN cards using the PLX9052 PCI bridge");
349MODULE_LICENSE("Dual MPL/GPL");
350
351static int __init orinoco_plx_init(void)
352{
353 printk(KERN_DEBUG "%s\n", version);
354 return pci_register_driver(&orinoco_plx_driver);
355}
356
357static void __exit orinoco_plx_exit(void)
358{
359 pci_unregister_driver(&orinoco_plx_driver);
360}
361
362module_init(orinoco_plx_init);
363module_exit(orinoco_plx_exit);
364
365
366
367
368
369
370
371
372