Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * tmspci.c: A generic network driver for TMS380-based PCI token ring cards. | |
3 | * | |
4 | * Written 1999 by Adam Fritzler | |
5 | * | |
6 | * This software may be used and distributed according to the terms | |
7 | * of the GNU General Public License, incorporated herein by reference. | |
8 | * | |
9 | * This driver module supports the following cards: | |
10 | * - SysKonnect TR4/16(+) PCI (SK-4590) | |
11 | * - SysKonnect TR4/16 PCI (SK-4591) | |
12 | * - Compaq TR 4/16 PCI | |
13 | * - Thomas-Conrad TC4048 4/16 PCI | |
14 | * - 3Com 3C339 Token Link Velocity | |
15 | * | |
16 | * Maintainer(s): | |
726a6459 | 17 | * AF Adam Fritzler |
1da177e4 LT |
18 | * |
19 | * Modification History: | |
20 | * 30-Dec-99 AF Split off from the tms380tr driver. | |
21 | * 22-Jan-00 AF Updated to use indirect read/writes | |
22 | * 23-Nov-00 JG New PCI API, cleanups | |
23 | * | |
24 | * TODO: | |
25 | * 1. See if we can use MMIO instead of port accesses | |
26 | * | |
27 | */ | |
28 | ||
29 | #include <linux/module.h> | |
30 | #include <linux/kernel.h> | |
31 | #include <linux/errno.h> | |
32 | #include <linux/pci.h> | |
33 | #include <linux/init.h> | |
34 | #include <linux/netdevice.h> | |
35 | #include <linux/trdevice.h> | |
36 | ||
37 | #include <asm/system.h> | |
38 | #include <asm/io.h> | |
39 | #include <asm/irq.h> | |
40 | ||
41 | #include "tms380tr.h" | |
42 | ||
43 | static char version[] __devinitdata = | |
44 | "tmspci.c: v1.02 23/11/2000 by Adam Fritzler\n"; | |
45 | ||
46 | #define TMS_PCI_IO_EXTENT 32 | |
47 | ||
48 | struct card_info { | |
49 | unsigned char nselout[2]; /* NSELOUT vals for 4mb([0]) and 16mb([1]) */ | |
50 | char *name; | |
51 | }; | |
52 | ||
53 | static struct card_info card_info_table[] = { | |
54 | { {0x03, 0x01}, "Compaq 4/16 TR PCI"}, | |
55 | { {0x03, 0x01}, "SK NET TR 4/16 PCI"}, | |
56 | { {0x03, 0x01}, "Thomas-Conrad TC4048 PCI 4/16"}, | |
57 | { {0x03, 0x01}, "3Com Token Link Velocity"}, | |
58 | }; | |
59 | ||
60 | static struct pci_device_id tmspci_pci_tbl[] = { | |
61 | { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_COMPAQ_TOKENRING, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, | |
62 | { PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_TR, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 }, | |
63 | { PCI_VENDOR_ID_TCONRAD, PCI_DEVICE_ID_TCONRAD_TOKENRING, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2 }, | |
64 | { PCI_VENDOR_ID_3COM, PCI_DEVICE_ID_3COM_3C339, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3 }, | |
65 | { } /* Terminating entry */ | |
66 | }; | |
67 | MODULE_DEVICE_TABLE(pci, tmspci_pci_tbl); | |
68 | ||
69 | MODULE_LICENSE("GPL"); | |
70 | ||
71 | static void tms_pci_read_eeprom(struct net_device *dev); | |
72 | static unsigned short tms_pci_setnselout_pins(struct net_device *dev); | |
73 | ||
74 | static unsigned short tms_pci_sifreadb(struct net_device *dev, unsigned short reg) | |
75 | { | |
76 | return inb(dev->base_addr + reg); | |
77 | } | |
78 | ||
79 | static unsigned short tms_pci_sifreadw(struct net_device *dev, unsigned short reg) | |
80 | { | |
81 | return inw(dev->base_addr + reg); | |
82 | } | |
83 | ||
84 | static void tms_pci_sifwriteb(struct net_device *dev, unsigned short val, unsigned short reg) | |
85 | { | |
86 | outb(val, dev->base_addr + reg); | |
87 | } | |
88 | ||
89 | static void tms_pci_sifwritew(struct net_device *dev, unsigned short val, unsigned short reg) | |
90 | { | |
91 | outw(val, dev->base_addr + reg); | |
92 | } | |
93 | ||
94 | static int __devinit tms_pci_attach(struct pci_dev *pdev, const struct pci_device_id *ent) | |
95 | { | |
96 | static int versionprinted; | |
97 | struct net_device *dev; | |
98 | struct net_local *tp; | |
0795af57 | 99 | int ret; |
1da177e4 LT |
100 | unsigned int pci_irq_line; |
101 | unsigned long pci_ioaddr; | |
102 | struct card_info *cardinfo = &card_info_table[ent->driver_data]; | |
504ff16c | 103 | |
1da177e4 LT |
104 | if (versionprinted++ == 0) |
105 | printk("%s", version); | |
106 | ||
107 | if (pci_enable_device(pdev)) | |
108 | return -EIO; | |
109 | ||
110 | /* Remove I/O space marker in bit 0. */ | |
111 | pci_irq_line = pdev->irq; | |
112 | pci_ioaddr = pci_resource_start (pdev, 0); | |
113 | ||
114 | /* At this point we have found a valid card. */ | |
115 | dev = alloc_trdev(sizeof(struct net_local)); | |
116 | if (!dev) | |
117 | return -ENOMEM; | |
1da177e4 LT |
118 | |
119 | if (!request_region(pci_ioaddr, TMS_PCI_IO_EXTENT, dev->name)) { | |
120 | ret = -EBUSY; | |
121 | goto err_out_trdev; | |
122 | } | |
123 | ||
1fb9df5d | 124 | ret = request_irq(pdev->irq, tms380tr_interrupt, IRQF_SHARED, |
1da177e4 LT |
125 | dev->name, dev); |
126 | if (ret) | |
127 | goto err_out_region; | |
128 | ||
129 | dev->base_addr = pci_ioaddr; | |
130 | dev->irq = pci_irq_line; | |
131 | dev->dma = 0; | |
132 | ||
133 | printk("%s: %s\n", dev->name, cardinfo->name); | |
134 | printk("%s: IO: %#4lx IRQ: %d\n", | |
135 | dev->name, dev->base_addr, dev->irq); | |
136 | ||
137 | tms_pci_read_eeprom(dev); | |
138 | ||
e174961c JB |
139 | printk("%s: Ring Station Address: %pM\n", |
140 | dev->name, dev->dev_addr); | |
1da177e4 | 141 | |
84c3ea01 | 142 | ret = tmsdev_init(dev, &pdev->dev); |
1da177e4 LT |
143 | if (ret) { |
144 | printk("%s: unable to get memory for dev->priv.\n", dev->name); | |
145 | goto err_out_irq; | |
146 | } | |
147 | ||
eda10531 | 148 | tp = netdev_priv(dev); |
1da177e4 LT |
149 | tp->setnselout = tms_pci_setnselout_pins; |
150 | ||
151 | tp->sifreadb = tms_pci_sifreadb; | |
152 | tp->sifreadw = tms_pci_sifreadw; | |
153 | tp->sifwriteb = tms_pci_sifwriteb; | |
154 | tp->sifwritew = tms_pci_sifwritew; | |
155 | ||
156 | memcpy(tp->ProductID, cardinfo->name, PROD_ID_SIZE + 1); | |
157 | ||
158 | tp->tmspriv = cardinfo; | |
159 | ||
160 | dev->open = tms380tr_open; | |
161 | dev->stop = tms380tr_close; | |
162 | pci_set_drvdata(pdev, dev); | |
163 | SET_NETDEV_DEV(dev, &pdev->dev); | |
164 | ||
165 | ret = register_netdev(dev); | |
166 | if (ret) | |
167 | goto err_out_tmsdev; | |
168 | ||
169 | return 0; | |
170 | ||
171 | err_out_tmsdev: | |
172 | pci_set_drvdata(pdev, NULL); | |
173 | tmsdev_term(dev); | |
174 | err_out_irq: | |
175 | free_irq(pdev->irq, dev); | |
176 | err_out_region: | |
177 | release_region(pci_ioaddr, TMS_PCI_IO_EXTENT); | |
178 | err_out_trdev: | |
179 | free_netdev(dev); | |
180 | return ret; | |
181 | } | |
182 | ||
183 | /* | |
184 | * Reads MAC address from adapter RAM, which should've read it from | |
185 | * the onboard ROM. | |
186 | * | |
187 | * Calling this on a board that does not support it can be a very | |
188 | * dangerous thing. The Madge board, for instance, will lock your | |
189 | * machine hard when this is called. Luckily, its supported in a | |
190 | * separate driver. --ASF | |
191 | */ | |
192 | static void tms_pci_read_eeprom(struct net_device *dev) | |
193 | { | |
194 | int i; | |
195 | ||
196 | /* Address: 0000:0000 */ | |
197 | tms_pci_sifwritew(dev, 0, SIFADX); | |
198 | tms_pci_sifwritew(dev, 0, SIFADR); | |
199 | ||
200 | /* Read six byte MAC address data */ | |
201 | dev->addr_len = 6; | |
202 | for(i = 0; i < 6; i++) | |
203 | dev->dev_addr[i] = tms_pci_sifreadw(dev, SIFINC) >> 8; | |
204 | } | |
205 | ||
206 | static unsigned short tms_pci_setnselout_pins(struct net_device *dev) | |
207 | { | |
208 | unsigned short val = 0; | |
eda10531 | 209 | struct net_local *tp = netdev_priv(dev); |
1da177e4 LT |
210 | struct card_info *cardinfo = tp->tmspriv; |
211 | ||
212 | if(tp->DataRate == SPEED_4) | |
213 | val |= cardinfo->nselout[0]; /* Set 4Mbps */ | |
214 | else | |
215 | val |= cardinfo->nselout[1]; /* Set 16Mbps */ | |
216 | return val; | |
217 | } | |
218 | ||
219 | static void __devexit tms_pci_detach (struct pci_dev *pdev) | |
220 | { | |
221 | struct net_device *dev = pci_get_drvdata(pdev); | |
222 | ||
644c12d7 | 223 | BUG_ON(!dev); |
1da177e4 LT |
224 | unregister_netdev(dev); |
225 | release_region(dev->base_addr, TMS_PCI_IO_EXTENT); | |
226 | free_irq(dev->irq, dev); | |
227 | tmsdev_term(dev); | |
228 | free_netdev(dev); | |
229 | pci_set_drvdata(pdev, NULL); | |
230 | } | |
231 | ||
232 | static struct pci_driver tms_pci_driver = { | |
233 | .name = "tmspci", | |
234 | .id_table = tmspci_pci_tbl, | |
235 | .probe = tms_pci_attach, | |
236 | .remove = __devexit_p(tms_pci_detach), | |
237 | }; | |
238 | ||
239 | static int __init tms_pci_init (void) | |
240 | { | |
241 | return pci_register_driver(&tms_pci_driver); | |
242 | } | |
243 | ||
244 | static void __exit tms_pci_rmmod (void) | |
245 | { | |
246 | pci_unregister_driver (&tms_pci_driver); | |
247 | } | |
248 | ||
249 | module_init(tms_pci_init); | |
250 | module_exit(tms_pci_rmmod); | |
251 |