Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * Linux ARCnet driver - COM20020 PCI support | |
3 | * Contemporary Controls PCI20 and SOHARD SH-ARC PCI | |
4 | * | |
5 | * Written 1994-1999 by Avery Pennarun, | |
6 | * based on an ISA version by David Woodhouse. | |
7 | * Written 1999-2000 by Martin Mares <mj@ucw.cz>. | |
8 | * Derived from skeleton.c by Donald Becker. | |
9 | * | |
10 | * Special thanks to Contemporary Controls, Inc. (www.ccontrols.com) | |
11 | * for sponsoring the further development of this driver. | |
12 | * | |
13 | * ********************** | |
14 | * | |
15 | * The original copyright of skeleton.c was as follows: | |
16 | * | |
17 | * skeleton.c Written 1993 by Donald Becker. | |
18 | * Copyright 1993 United States Government as represented by the | |
19 | * Director, National Security Agency. This software may only be used | |
20 | * and distributed according to the terms of the GNU General Public License as | |
21 | * modified by SRC, incorporated herein by reference. | |
22 | * | |
23 | * ********************** | |
24 | * | |
25 | * For more details, see drivers/net/arcnet.c | |
26 | * | |
27 | * ********************** | |
28 | */ | |
29 | #include <linux/module.h> | |
30 | #include <linux/moduleparam.h> | |
31 | #include <linux/kernel.h> | |
32 | #include <linux/types.h> | |
33 | #include <linux/ioport.h> | |
1da177e4 LT |
34 | #include <linux/errno.h> |
35 | #include <linux/netdevice.h> | |
36 | #include <linux/init.h> | |
a6b7a407 | 37 | #include <linux/interrupt.h> |
1da177e4 LT |
38 | #include <linux/pci.h> |
39 | #include <linux/arcdevice.h> | |
40 | #include <linux/com20020.h> | |
c51da42a | 41 | #include <linux/list.h> |
1da177e4 LT |
42 | |
43 | #include <asm/io.h> | |
44 | ||
45 | ||
46 | #define VERSION "arcnet: COM20020 PCI support\n" | |
47 | ||
48 | /* Module parameters */ | |
49 | ||
50 | static int node; | |
51 | static char device[9]; /* use eg. device="arc1" to change name */ | |
52 | static int timeout = 3; | |
53 | static int backplane; | |
54 | static int clockp; | |
55 | static int clockm; | |
56 | ||
57 | module_param(node, int, 0); | |
58 | module_param_string(device, device, sizeof(device), 0); | |
59 | module_param(timeout, int, 0); | |
60 | module_param(backplane, int, 0); | |
61 | module_param(clockp, int, 0); | |
62 | module_param(clockm, int, 0); | |
63 | MODULE_LICENSE("GPL"); | |
64 | ||
c51da42a MG |
65 | static void com20020pci_remove(struct pci_dev *pdev); |
66 | ||
7c47bab6 | 67 | static int com20020pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) |
1da177e4 | 68 | { |
8c14f9c7 | 69 | struct com20020_pci_card_info *ci; |
1da177e4 LT |
70 | struct net_device *dev; |
71 | struct arcnet_local *lp; | |
c51da42a MG |
72 | struct com20020_priv *priv; |
73 | int i, ioaddr, ret; | |
74 | struct resource *r; | |
1da177e4 LT |
75 | |
76 | if (pci_enable_device(pdev)) | |
77 | return -EIO; | |
a1799af4 | 78 | |
c51da42a MG |
79 | priv = devm_kzalloc(&pdev->dev, sizeof(struct com20020_priv), |
80 | GFP_KERNEL); | |
8c14f9c7 | 81 | ci = (struct com20020_pci_card_info *)id->driver_data; |
c51da42a MG |
82 | priv->ci = ci; |
83 | ||
84 | INIT_LIST_HEAD(&priv->list_dev); | |
85 | ||
86 | ||
87 | for (i = 0; i < ci->devcount; i++) { | |
88 | struct com20020_pci_channel_map *cm = &ci->chan_map_tbl[i]; | |
89 | struct com20020_dev *card; | |
90 | ||
91 | dev = alloc_arcdev(device); | |
92 | if (!dev) { | |
93 | ret = -ENOMEM; | |
94 | goto out_port; | |
95 | } | |
96 | ||
97 | dev->netdev_ops = &com20020_netdev_ops; | |
98 | ||
99 | lp = netdev_priv(dev); | |
100 | ||
101 | BUGMSG(D_NORMAL, "%s Controls\n", ci->name); | |
102 | ioaddr = pci_resource_start(pdev, cm->bar) + cm->offset; | |
103 | ||
104 | r = devm_request_region(&pdev->dev, ioaddr, cm->size, | |
105 | "com20020-pci"); | |
106 | if (!r) { | |
107 | pr_err("IO region %xh-%xh already allocated.\n", | |
108 | ioaddr, ioaddr + cm->size - 1); | |
109 | ret = -EBUSY; | |
110 | goto out_port; | |
111 | } | |
112 | ||
113 | /* Dummy access after Reset | |
114 | * ARCNET controller needs | |
115 | * this access to detect bustype | |
116 | */ | |
117 | outb(0x00, ioaddr + 1); | |
118 | inb(ioaddr + 1); | |
119 | ||
120 | dev->base_addr = ioaddr; | |
121 | dev->dev_addr[0] = node; | |
122 | dev->irq = pdev->irq; | |
123 | lp->card_name = "PCI COM20020"; | |
124 | lp->card_flags = ci->flags; | |
125 | lp->backplane = backplane; | |
126 | lp->clockp = clockp & 7; | |
127 | lp->clockm = clockm & 3; | |
128 | lp->timeout = timeout; | |
129 | lp->hw.owner = THIS_MODULE; | |
130 | ||
131 | if (ASTATUS() == 0xFF) { | |
132 | pr_err("IO address %Xh is empty!\n", ioaddr); | |
133 | ret = -EIO; | |
134 | goto out_port; | |
135 | } | |
136 | if (com20020_check(dev)) { | |
137 | ret = -EIO; | |
138 | goto out_port; | |
139 | } | |
140 | ||
141 | card = devm_kzalloc(&pdev->dev, sizeof(struct com20020_dev), | |
142 | GFP_KERNEL); | |
143 | if (!card) { | |
144 | pr_err("%s out of memory!\n", __func__); | |
145 | return -ENOMEM; | |
146 | } | |
147 | ||
148 | card->index = i; | |
149 | card->pci_priv = priv; | |
150 | card->dev = dev; | |
151 | ||
152 | dev_set_drvdata(&dev->dev, card); | |
153 | ||
154 | ret = com20020_found(dev, IRQF_SHARED); | |
155 | if (ret) | |
156 | goto out_port; | |
157 | ||
158 | list_add(&card->list, &priv->list_dev); | |
1da177e4 LT |
159 | } |
160 | ||
c51da42a | 161 | pci_set_drvdata(pdev, priv); |
1da177e4 LT |
162 | |
163 | return 0; | |
164 | ||
165 | out_port: | |
c51da42a MG |
166 | com20020pci_remove(pdev); |
167 | return ret; | |
1da177e4 LT |
168 | } |
169 | ||
7c47bab6 | 170 | static void com20020pci_remove(struct pci_dev *pdev) |
1da177e4 | 171 | { |
c51da42a MG |
172 | struct com20020_dev *card, *tmpcard; |
173 | struct com20020_priv *priv; | |
174 | ||
175 | priv = pci_get_drvdata(pdev); | |
176 | ||
177 | list_for_each_entry_safe(card, tmpcard, &priv->list_dev, list) { | |
178 | struct net_device *dev = card->dev; | |
179 | ||
180 | unregister_netdev(dev); | |
181 | free_irq(dev->irq, dev); | |
182 | free_netdev(dev); | |
183 | } | |
1da177e4 LT |
184 | } |
185 | ||
8c14f9c7 MG |
186 | static struct com20020_pci_card_info card_info_10mbit = { |
187 | .name = "ARC-PCI", | |
188 | .devcount = 1, | |
189 | .chan_map_tbl = { | |
190 | { 2, 0x00, 0x08 }, | |
191 | }, | |
192 | .flags = ARC_CAN_10MBIT, | |
193 | }; | |
194 | ||
195 | static struct com20020_pci_card_info card_info_5mbit = { | |
196 | .name = "ARC-PCI", | |
197 | .devcount = 1, | |
198 | .chan_map_tbl = { | |
199 | { 2, 0x00, 0x08 }, | |
200 | }, | |
201 | .flags = ARC_IS_5MBIT, | |
202 | }; | |
203 | ||
204 | static struct com20020_pci_card_info card_info_sohard = { | |
205 | .name = "PLX-PCI", | |
206 | .devcount = 1, | |
207 | /* SOHARD needs PCI base addr 4 */ | |
208 | .chan_map_tbl = { | |
209 | {4, 0x00, 0x08}, | |
210 | }, | |
211 | .flags = ARC_CAN_10MBIT, | |
212 | }; | |
213 | ||
9baa3c34 | 214 | static const struct pci_device_id com20020pci_id_table[] = { |
8c14f9c7 MG |
215 | { |
216 | 0x1571, 0xa001, | |
217 | PCI_ANY_ID, PCI_ANY_ID, | |
218 | 0, 0, | |
219 | 0, | |
220 | }, | |
221 | { | |
222 | 0x1571, 0xa002, | |
223 | PCI_ANY_ID, PCI_ANY_ID, | |
224 | 0, 0, | |
225 | 0, | |
226 | }, | |
227 | { | |
228 | 0x1571, 0xa003, | |
229 | PCI_ANY_ID, PCI_ANY_ID, | |
230 | 0, 0, | |
231 | 0 | |
232 | }, | |
233 | { | |
234 | 0x1571, 0xa004, | |
235 | PCI_ANY_ID, PCI_ANY_ID, | |
236 | 0, 0, | |
237 | 0, | |
238 | }, | |
239 | { | |
240 | 0x1571, 0xa005, | |
241 | PCI_ANY_ID, PCI_ANY_ID, | |
242 | 0, 0, | |
243 | 0 | |
244 | }, | |
245 | { | |
246 | 0x1571, 0xa006, | |
247 | PCI_ANY_ID, PCI_ANY_ID, | |
248 | 0, 0, | |
249 | 0 | |
250 | }, | |
251 | { | |
252 | 0x1571, 0xa007, | |
253 | PCI_ANY_ID, PCI_ANY_ID, | |
254 | 0, 0, | |
255 | 0 | |
256 | }, | |
257 | { | |
258 | 0x1571, 0xa008, | |
259 | PCI_ANY_ID, PCI_ANY_ID, | |
260 | 0, 0, | |
261 | 0 | |
262 | }, | |
263 | { | |
264 | 0x1571, 0xa009, | |
265 | PCI_ANY_ID, PCI_ANY_ID, | |
266 | 0, 0, | |
267 | (kernel_ulong_t)&card_info_5mbit | |
268 | }, | |
269 | { | |
270 | 0x1571, 0xa00a, | |
271 | PCI_ANY_ID, PCI_ANY_ID, | |
272 | 0, 0, | |
273 | (kernel_ulong_t)&card_info_5mbit | |
274 | }, | |
275 | { | |
276 | 0x1571, 0xa00b, | |
277 | PCI_ANY_ID, PCI_ANY_ID, | |
278 | 0, 0, | |
279 | (kernel_ulong_t)&card_info_5mbit | |
280 | }, | |
281 | { | |
282 | 0x1571, 0xa00c, | |
283 | PCI_ANY_ID, PCI_ANY_ID, | |
284 | 0, 0, | |
285 | (kernel_ulong_t)&card_info_5mbit | |
286 | }, | |
287 | { | |
288 | 0x1571, 0xa00d, | |
289 | PCI_ANY_ID, PCI_ANY_ID, | |
290 | 0, 0, | |
291 | (kernel_ulong_t)&card_info_5mbit | |
292 | }, | |
293 | { | |
294 | 0x1571, 0xa00e, | |
295 | PCI_ANY_ID, PCI_ANY_ID, | |
296 | 0, 0, | |
297 | (kernel_ulong_t)&card_info_5mbit | |
298 | }, | |
299 | { | |
300 | 0x1571, 0xa201, | |
301 | PCI_ANY_ID, PCI_ANY_ID, | |
302 | 0, 0, | |
303 | (kernel_ulong_t)&card_info_10mbit | |
304 | }, | |
305 | { | |
306 | 0x1571, 0xa202, | |
307 | PCI_ANY_ID, PCI_ANY_ID, | |
308 | 0, 0, | |
309 | (kernel_ulong_t)&card_info_10mbit | |
310 | }, | |
311 | { | |
312 | 0x1571, 0xa203, | |
313 | PCI_ANY_ID, PCI_ANY_ID, | |
314 | 0, 0, | |
315 | (kernel_ulong_t)&card_info_10mbit | |
316 | }, | |
317 | { | |
318 | 0x1571, 0xa204, | |
319 | PCI_ANY_ID, PCI_ANY_ID, | |
320 | 0, 0, | |
321 | (kernel_ulong_t)&card_info_10mbit | |
322 | }, | |
323 | { | |
324 | 0x1571, 0xa205, | |
325 | PCI_ANY_ID, PCI_ANY_ID, | |
326 | 0, 0, | |
327 | (kernel_ulong_t)&card_info_10mbit | |
328 | }, | |
329 | { | |
330 | 0x1571, 0xa206, | |
331 | PCI_ANY_ID, PCI_ANY_ID, | |
332 | 0, 0, | |
333 | (kernel_ulong_t)&card_info_10mbit | |
334 | }, | |
335 | { | |
336 | 0x10B5, 0x9030, | |
337 | 0x10B5, 0x2978, | |
338 | 0, 0, | |
339 | (kernel_ulong_t)&card_info_sohard | |
340 | }, | |
341 | { | |
342 | 0x10B5, 0x9050, | |
343 | 0x10B5, 0x2273, | |
344 | 0, 0, | |
345 | (kernel_ulong_t)&card_info_sohard | |
346 | }, | |
347 | { | |
348 | 0x14BA, 0x6000, | |
349 | PCI_ANY_ID, PCI_ANY_ID, | |
350 | 0, 0, | |
351 | (kernel_ulong_t)&card_info_10mbit | |
352 | }, | |
353 | { | |
354 | 0x10B5, 0x2200, | |
355 | PCI_ANY_ID, PCI_ANY_ID, | |
356 | 0, 0, | |
357 | (kernel_ulong_t)&card_info_10mbit | |
358 | }, | |
359 | { 0, } | |
1da177e4 LT |
360 | }; |
361 | ||
362 | MODULE_DEVICE_TABLE(pci, com20020pci_id_table); | |
363 | ||
364 | static struct pci_driver com20020pci_driver = { | |
365 | .name = "com20020", | |
366 | .id_table = com20020pci_id_table, | |
367 | .probe = com20020pci_probe, | |
7c47bab6 | 368 | .remove = com20020pci_remove, |
1da177e4 LT |
369 | }; |
370 | ||
371 | static int __init com20020pci_init(void) | |
372 | { | |
373 | BUGLVL(D_NORMAL) printk(VERSION); | |
29917620 | 374 | return pci_register_driver(&com20020pci_driver); |
1da177e4 LT |
375 | } |
376 | ||
377 | static void __exit com20020pci_cleanup(void) | |
378 | { | |
379 | pci_unregister_driver(&com20020pci_driver); | |
380 | } | |
381 | ||
382 | module_init(com20020pci_init) | |
383 | module_exit(com20020pci_cleanup) |