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
30 #define pr_fmt(fmt) "arcnet:" KBUILD_MODNAME ": " fmt
31
32 #include <linux/module.h>
33 #include <linux/moduleparam.h>
34 #include <linux/kernel.h>
35 #include <linux/types.h>
36 #include <linux/ioport.h>
37 #include <linux/errno.h>
38 #include <linux/netdevice.h>
39 #include <linux/init.h>
40 #include <linux/interrupt.h>
41 #include <linux/pci.h>
42 #include <linux/list.h>
43 #include <linux/io.h>
44 #include <linux/leds.h>
45
46 #include "arcdevice.h"
47 #include "com20020.h"
48
49 /* Module parameters */
50
51 static int node;
52 static char device[9]; /* use eg. device="arc1" to change name */
53 static int timeout = 3;
54 static int backplane;
55 static int clockp;
56 static int clockm;
57
58 module_param(node, int, 0);
59 module_param_string(device, device, sizeof(device), 0);
60 module_param(timeout, int, 0);
61 module_param(backplane, int, 0);
62 module_param(clockp, int, 0);
63 module_param(clockm, int, 0);
64 MODULE_LICENSE("GPL");
65
led_tx_set(struct led_classdev * led_cdev,enum led_brightness value)66 static void led_tx_set(struct led_classdev *led_cdev,
67 enum led_brightness value)
68 {
69 struct com20020_dev *card;
70 struct com20020_priv *priv;
71 struct com20020_pci_card_info *ci;
72
73 card = container_of(led_cdev, struct com20020_dev, tx_led);
74
75 priv = card->pci_priv;
76 ci = priv->ci;
77
78 outb(!!value, priv->misc + ci->leds[card->index].green);
79 }
80
led_recon_set(struct led_classdev * led_cdev,enum led_brightness value)81 static void led_recon_set(struct led_classdev *led_cdev,
82 enum led_brightness value)
83 {
84 struct com20020_dev *card;
85 struct com20020_priv *priv;
86 struct com20020_pci_card_info *ci;
87
88 card = container_of(led_cdev, struct com20020_dev, recon_led);
89
90 priv = card->pci_priv;
91 ci = priv->ci;
92
93 outb(!!value, priv->misc + ci->leds[card->index].red);
94 }
95
backplane_mode_show(struct device * dev,struct device_attribute * attr,char * buf)96 static ssize_t backplane_mode_show(struct device *dev,
97 struct device_attribute *attr,
98 char *buf)
99 {
100 struct net_device *net_dev = to_net_dev(dev);
101 struct arcnet_local *lp = netdev_priv(net_dev);
102
103 return sprintf(buf, "%s\n", lp->backplane ? "true" : "false");
104 }
105 static DEVICE_ATTR_RO(backplane_mode);
106
107 static struct attribute *com20020_state_attrs[] = {
108 &dev_attr_backplane_mode.attr,
109 NULL,
110 };
111
112 static const struct attribute_group com20020_state_group = {
113 .name = NULL,
114 .attrs = com20020_state_attrs,
115 };
116
117 static void com20020pci_remove(struct pci_dev *pdev);
118
com20020pci_probe(struct pci_dev * pdev,const struct pci_device_id * id)119 static int com20020pci_probe(struct pci_dev *pdev,
120 const struct pci_device_id *id)
121 {
122 struct com20020_pci_card_info *ci;
123 struct com20020_pci_channel_map *mm;
124 struct net_device *dev;
125 struct arcnet_local *lp;
126 struct com20020_priv *priv;
127 int i, ioaddr, ret;
128 struct resource *r;
129
130 if (pci_enable_device(pdev))
131 return -EIO;
132
133 priv = devm_kzalloc(&pdev->dev, sizeof(struct com20020_priv),
134 GFP_KERNEL);
135 if (!priv)
136 return -ENOMEM;
137
138 ci = (struct com20020_pci_card_info *)id->driver_data;
139 if (!ci)
140 return -EINVAL;
141
142 priv->ci = ci;
143 mm = &ci->misc_map;
144
145 INIT_LIST_HEAD(&priv->list_dev);
146
147 if (mm->size) {
148 ioaddr = pci_resource_start(pdev, mm->bar) + mm->offset;
149 r = devm_request_region(&pdev->dev, ioaddr, mm->size,
150 "com20020-pci");
151 if (!r) {
152 pr_err("IO region %xh-%xh already allocated.\n",
153 ioaddr, ioaddr + mm->size - 1);
154 return -EBUSY;
155 }
156 priv->misc = ioaddr;
157 }
158
159 for (i = 0; i < ci->devcount; i++) {
160 struct com20020_pci_channel_map *cm = &ci->chan_map_tbl[i];
161 struct com20020_dev *card;
162 int dev_id_mask = 0xf;
163
164 dev = alloc_arcdev(device);
165 if (!dev) {
166 ret = -ENOMEM;
167 goto out_port;
168 }
169 dev->dev_port = i;
170
171 dev->netdev_ops = &com20020_netdev_ops;
172
173 lp = netdev_priv(dev);
174
175 arc_printk(D_NORMAL, dev, "%s Controls\n", ci->name);
176 ioaddr = pci_resource_start(pdev, cm->bar) + cm->offset;
177
178 r = devm_request_region(&pdev->dev, ioaddr, cm->size,
179 "com20020-pci");
180 if (!r) {
181 pr_err("IO region %xh-%xh already allocated\n",
182 ioaddr, ioaddr + cm->size - 1);
183 ret = -EBUSY;
184 goto out_port;
185 }
186
187 /* Dummy access after Reset
188 * ARCNET controller needs
189 * this access to detect bustype
190 */
191 arcnet_outb(0x00, ioaddr, COM20020_REG_W_COMMAND);
192 arcnet_inb(ioaddr, COM20020_REG_R_DIAGSTAT);
193
194 SET_NETDEV_DEV(dev, &pdev->dev);
195 dev->base_addr = ioaddr;
196 dev->dev_addr[0] = node;
197 dev->sysfs_groups[0] = &com20020_state_group;
198 dev->irq = pdev->irq;
199 lp->card_name = "PCI COM20020";
200 lp->card_flags = ci->flags;
201 lp->backplane = backplane;
202 lp->clockp = clockp & 7;
203 lp->clockm = clockm & 3;
204 lp->timeout = timeout;
205 lp->hw.owner = THIS_MODULE;
206
207 lp->backplane = (inb(priv->misc) >> (2 + i)) & 0x1;
208
209 if (!strncmp(ci->name, "EAE PLX-PCI FB2", 15))
210 lp->backplane = 1;
211
212 /* Get the dev_id from the PLX rotary coder */
213 if (!strncmp(ci->name, "EAE PLX-PCI MA1", 15))
214 dev_id_mask = 0x3;
215 dev->dev_id = (inb(priv->misc + ci->rotary) >> 4) & dev_id_mask;
216
217 snprintf(dev->name, sizeof(dev->name), "arc%d-%d", dev->dev_id, i);
218
219 if (arcnet_inb(ioaddr, COM20020_REG_R_STATUS) == 0xFF) {
220 pr_err("IO address %Xh is empty!\n", ioaddr);
221 ret = -EIO;
222 goto out_port;
223 }
224 if (com20020_check(dev)) {
225 ret = -EIO;
226 goto out_port;
227 }
228
229 card = devm_kzalloc(&pdev->dev, sizeof(struct com20020_dev),
230 GFP_KERNEL);
231 if (!card) {
232 ret = -ENOMEM;
233 goto out_port;
234 }
235
236 card->index = i;
237 card->pci_priv = priv;
238 card->tx_led.brightness_set = led_tx_set;
239 card->tx_led.default_trigger = devm_kasprintf(&pdev->dev,
240 GFP_KERNEL, "arc%d-%d-tx",
241 dev->dev_id, i);
242 card->tx_led.name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
243 "pci:green:tx:%d-%d",
244 dev->dev_id, i);
245
246 card->tx_led.dev = &dev->dev;
247 card->recon_led.brightness_set = led_recon_set;
248 card->recon_led.default_trigger = devm_kasprintf(&pdev->dev,
249 GFP_KERNEL, "arc%d-%d-recon",
250 dev->dev_id, i);
251 card->recon_led.name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
252 "pci:red:recon:%d-%d",
253 dev->dev_id, i);
254 card->recon_led.dev = &dev->dev;
255 card->dev = dev;
256
257 ret = devm_led_classdev_register(&pdev->dev, &card->tx_led);
258 if (ret)
259 goto out_port;
260
261 ret = devm_led_classdev_register(&pdev->dev, &card->recon_led);
262 if (ret)
263 goto out_port;
264
265 dev_set_drvdata(&dev->dev, card);
266
267 ret = com20020_found(dev, IRQF_SHARED);
268 if (ret)
269 goto out_port;
270
271 devm_arcnet_led_init(dev, dev->dev_id, i);
272
273 list_add(&card->list, &priv->list_dev);
274 }
275
276 pci_set_drvdata(pdev, priv);
277
278 return 0;
279
280 out_port:
281 com20020pci_remove(pdev);
282 return ret;
283 }
284
com20020pci_remove(struct pci_dev * pdev)285 static void com20020pci_remove(struct pci_dev *pdev)
286 {
287 struct com20020_dev *card, *tmpcard;
288 struct com20020_priv *priv;
289
290 priv = pci_get_drvdata(pdev);
291
292 list_for_each_entry_safe(card, tmpcard, &priv->list_dev, list) {
293 struct net_device *dev = card->dev;
294
295 unregister_netdev(dev);
296 free_irq(dev->irq, dev);
297 free_arcdev(dev);
298 }
299 }
300
301 static struct com20020_pci_card_info card_info_10mbit = {
302 .name = "ARC-PCI",
303 .devcount = 1,
304 .chan_map_tbl = {
305 {
306 .bar = 2,
307 .offset = 0x00,
308 .size = 0x08,
309 },
310 },
311 .flags = ARC_CAN_10MBIT,
312 };
313
314 static struct com20020_pci_card_info card_info_5mbit = {
315 .name = "ARC-PCI",
316 .devcount = 1,
317 .chan_map_tbl = {
318 {
319 .bar = 2,
320 .offset = 0x00,
321 .size = 0x08,
322 },
323 },
324 .flags = ARC_IS_5MBIT,
325 };
326
327 static struct com20020_pci_card_info card_info_sohard = {
328 .name = "PLX-PCI",
329 .devcount = 1,
330 /* SOHARD needs PCI base addr 4 */
331 .chan_map_tbl = {
332 {
333 .bar = 4,
334 .offset = 0x00,
335 .size = 0x08
336 },
337 },
338 .flags = ARC_CAN_10MBIT,
339 };
340
341 static struct com20020_pci_card_info card_info_eae_arc1 = {
342 .name = "EAE PLX-PCI ARC1",
343 .devcount = 1,
344 .chan_map_tbl = {
345 {
346 .bar = 2,
347 .offset = 0x00,
348 .size = 0x08,
349 },
350 },
351 .misc_map = {
352 .bar = 2,
353 .offset = 0x10,
354 .size = 0x04,
355 },
356 .leds = {
357 {
358 .green = 0x0,
359 .red = 0x1,
360 },
361 },
362 .rotary = 0x0,
363 .flags = ARC_CAN_10MBIT,
364 };
365
366 static struct com20020_pci_card_info card_info_eae_ma1 = {
367 .name = "EAE PLX-PCI MA1",
368 .devcount = 2,
369 .chan_map_tbl = {
370 {
371 .bar = 2,
372 .offset = 0x00,
373 .size = 0x08,
374 }, {
375 .bar = 2,
376 .offset = 0x08,
377 .size = 0x08,
378 }
379 },
380 .misc_map = {
381 .bar = 2,
382 .offset = 0x10,
383 .size = 0x04,
384 },
385 .leds = {
386 {
387 .green = 0x0,
388 .red = 0x1,
389 }, {
390 .green = 0x2,
391 .red = 0x3,
392 },
393 },
394 .rotary = 0x0,
395 .flags = ARC_CAN_10MBIT,
396 };
397
398 static struct com20020_pci_card_info card_info_eae_fb2 = {
399 .name = "EAE PLX-PCI FB2",
400 .devcount = 1,
401 .chan_map_tbl = {
402 {
403 .bar = 2,
404 .offset = 0x00,
405 .size = 0x08,
406 },
407 },
408 .misc_map = {
409 .bar = 2,
410 .offset = 0x10,
411 .size = 0x04,
412 },
413 .leds = {
414 {
415 .green = 0x0,
416 .red = 0x1,
417 },
418 },
419 .rotary = 0x0,
420 .flags = ARC_CAN_10MBIT,
421 };
422
423 static const struct pci_device_id com20020pci_id_table[] = {
424 {
425 0x1571, 0xa001,
426 PCI_ANY_ID, PCI_ANY_ID,
427 0, 0,
428 0,
429 },
430 {
431 0x1571, 0xa002,
432 PCI_ANY_ID, PCI_ANY_ID,
433 0, 0,
434 0,
435 },
436 {
437 0x1571, 0xa003,
438 PCI_ANY_ID, PCI_ANY_ID,
439 0, 0,
440 0
441 },
442 {
443 0x1571, 0xa004,
444 PCI_ANY_ID, PCI_ANY_ID,
445 0, 0,
446 0,
447 },
448 {
449 0x1571, 0xa005,
450 PCI_ANY_ID, PCI_ANY_ID,
451 0, 0,
452 0
453 },
454 {
455 0x1571, 0xa006,
456 PCI_ANY_ID, PCI_ANY_ID,
457 0, 0,
458 0
459 },
460 {
461 0x1571, 0xa007,
462 PCI_ANY_ID, PCI_ANY_ID,
463 0, 0,
464 0
465 },
466 {
467 0x1571, 0xa008,
468 PCI_ANY_ID, PCI_ANY_ID,
469 0, 0,
470 0
471 },
472 {
473 0x1571, 0xa009,
474 PCI_ANY_ID, PCI_ANY_ID,
475 0, 0,
476 (kernel_ulong_t)&card_info_5mbit
477 },
478 {
479 0x1571, 0xa00a,
480 PCI_ANY_ID, PCI_ANY_ID,
481 0, 0,
482 (kernel_ulong_t)&card_info_5mbit
483 },
484 {
485 0x1571, 0xa00b,
486 PCI_ANY_ID, PCI_ANY_ID,
487 0, 0,
488 (kernel_ulong_t)&card_info_5mbit
489 },
490 {
491 0x1571, 0xa00c,
492 PCI_ANY_ID, PCI_ANY_ID,
493 0, 0,
494 (kernel_ulong_t)&card_info_5mbit
495 },
496 {
497 0x1571, 0xa00d,
498 PCI_ANY_ID, PCI_ANY_ID,
499 0, 0,
500 (kernel_ulong_t)&card_info_5mbit
501 },
502 {
503 0x1571, 0xa00e,
504 PCI_ANY_ID, PCI_ANY_ID,
505 0, 0,
506 (kernel_ulong_t)&card_info_5mbit
507 },
508 {
509 0x1571, 0xa201,
510 PCI_ANY_ID, PCI_ANY_ID,
511 0, 0,
512 (kernel_ulong_t)&card_info_10mbit
513 },
514 {
515 0x1571, 0xa202,
516 PCI_ANY_ID, PCI_ANY_ID,
517 0, 0,
518 (kernel_ulong_t)&card_info_10mbit
519 },
520 {
521 0x1571, 0xa203,
522 PCI_ANY_ID, PCI_ANY_ID,
523 0, 0,
524 (kernel_ulong_t)&card_info_10mbit
525 },
526 {
527 0x1571, 0xa204,
528 PCI_ANY_ID, PCI_ANY_ID,
529 0, 0,
530 (kernel_ulong_t)&card_info_10mbit
531 },
532 {
533 0x1571, 0xa205,
534 PCI_ANY_ID, PCI_ANY_ID,
535 0, 0,
536 (kernel_ulong_t)&card_info_10mbit
537 },
538 {
539 0x1571, 0xa206,
540 PCI_ANY_ID, PCI_ANY_ID,
541 0, 0,
542 (kernel_ulong_t)&card_info_10mbit
543 },
544 {
545 0x10B5, 0x9030,
546 0x10B5, 0x2978,
547 0, 0,
548 (kernel_ulong_t)&card_info_sohard
549 },
550 {
551 0x10B5, 0x9050,
552 0x10B5, 0x2273,
553 0, 0,
554 (kernel_ulong_t)&card_info_sohard
555 },
556 {
557 0x10B5, 0x9050,
558 0x10B5, 0x3263,
559 0, 0,
560 (kernel_ulong_t)&card_info_eae_arc1
561 },
562 {
563 0x10B5, 0x9050,
564 0x10B5, 0x3292,
565 0, 0,
566 (kernel_ulong_t)&card_info_eae_ma1
567 },
568 {
569 0x10B5, 0x9050,
570 0x10B5, 0x3294,
571 0, 0,
572 (kernel_ulong_t)&card_info_eae_fb2
573 },
574 {
575 0x14BA, 0x6000,
576 PCI_ANY_ID, PCI_ANY_ID,
577 0, 0,
578 (kernel_ulong_t)&card_info_10mbit
579 },
580 {
581 0x10B5, 0x2200,
582 PCI_ANY_ID, PCI_ANY_ID,
583 0, 0,
584 (kernel_ulong_t)&card_info_10mbit
585 },
586 { 0, }
587 };
588
589 MODULE_DEVICE_TABLE(pci, com20020pci_id_table);
590
591 static struct pci_driver com20020pci_driver = {
592 .name = "com20020",
593 .id_table = com20020pci_id_table,
594 .probe = com20020pci_probe,
595 .remove = com20020pci_remove,
596 };
597
com20020pci_init(void)598 static int __init com20020pci_init(void)
599 {
600 if (BUGLVL(D_NORMAL))
601 pr_info("%s\n", "COM20020 PCI support");
602 return pci_register_driver(&com20020pci_driver);
603 }
604
com20020pci_cleanup(void)605 static void __exit com20020pci_cleanup(void)
606 {
607 pci_unregister_driver(&com20020pci_driver);
608 }
609
610 module_init(com20020pci_init)
611 module_exit(com20020pci_cleanup)
612