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): | |
17 | * AF Adam Fritzler mid@auk.cx | |
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; | |
99 | int i, ret; | |
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; | |
118 | SET_MODULE_OWNER(dev); | |
119 | ||
120 | if (!request_region(pci_ioaddr, TMS_PCI_IO_EXTENT, dev->name)) { | |
121 | ret = -EBUSY; | |
122 | goto err_out_trdev; | |
123 | } | |
124 | ||
1fb9df5d | 125 | ret = request_irq(pdev->irq, tms380tr_interrupt, IRQF_SHARED, |
1da177e4 LT |
126 | dev->name, dev); |
127 | if (ret) | |
128 | goto err_out_region; | |
129 | ||
130 | dev->base_addr = pci_ioaddr; | |
131 | dev->irq = pci_irq_line; | |
132 | dev->dma = 0; | |
133 | ||
134 | printk("%s: %s\n", dev->name, cardinfo->name); | |
135 | printk("%s: IO: %#4lx IRQ: %d\n", | |
136 | dev->name, dev->base_addr, dev->irq); | |
137 | ||
138 | tms_pci_read_eeprom(dev); | |
139 | ||
140 | printk("%s: Ring Station Address: ", dev->name); | |
141 | printk("%2.2x", dev->dev_addr[0]); | |
142 | for (i = 1; i < 6; i++) | |
143 | printk(":%2.2x", dev->dev_addr[i]); | |
144 | printk("\n"); | |
145 | ||
84c3ea01 | 146 | ret = tmsdev_init(dev, &pdev->dev); |
1da177e4 LT |
147 | if (ret) { |
148 | printk("%s: unable to get memory for dev->priv.\n", dev->name); | |
149 | goto err_out_irq; | |
150 | } | |
151 | ||
152 | tp = dev->priv; | |
153 | tp->setnselout = tms_pci_setnselout_pins; | |
154 | ||
155 | tp->sifreadb = tms_pci_sifreadb; | |
156 | tp->sifreadw = tms_pci_sifreadw; | |
157 | tp->sifwriteb = tms_pci_sifwriteb; | |
158 | tp->sifwritew = tms_pci_sifwritew; | |
159 | ||
160 | memcpy(tp->ProductID, cardinfo->name, PROD_ID_SIZE + 1); | |
161 | ||
162 | tp->tmspriv = cardinfo; | |
163 | ||
164 | dev->open = tms380tr_open; | |
165 | dev->stop = tms380tr_close; | |
166 | pci_set_drvdata(pdev, dev); | |
167 | SET_NETDEV_DEV(dev, &pdev->dev); | |
168 | ||
169 | ret = register_netdev(dev); | |
170 | if (ret) | |
171 | goto err_out_tmsdev; | |
172 | ||
173 | return 0; | |
174 | ||
175 | err_out_tmsdev: | |
176 | pci_set_drvdata(pdev, NULL); | |
177 | tmsdev_term(dev); | |
178 | err_out_irq: | |
179 | free_irq(pdev->irq, dev); | |
180 | err_out_region: | |
181 | release_region(pci_ioaddr, TMS_PCI_IO_EXTENT); | |
182 | err_out_trdev: | |
183 | free_netdev(dev); | |
184 | return ret; | |
185 | } | |
186 | ||
187 | /* | |
188 | * Reads MAC address from adapter RAM, which should've read it from | |
189 | * the onboard ROM. | |
190 | * | |
191 | * Calling this on a board that does not support it can be a very | |
192 | * dangerous thing. The Madge board, for instance, will lock your | |
193 | * machine hard when this is called. Luckily, its supported in a | |
194 | * separate driver. --ASF | |
195 | */ | |
196 | static void tms_pci_read_eeprom(struct net_device *dev) | |
197 | { | |
198 | int i; | |
199 | ||
200 | /* Address: 0000:0000 */ | |
201 | tms_pci_sifwritew(dev, 0, SIFADX); | |
202 | tms_pci_sifwritew(dev, 0, SIFADR); | |
203 | ||
204 | /* Read six byte MAC address data */ | |
205 | dev->addr_len = 6; | |
206 | for(i = 0; i < 6; i++) | |
207 | dev->dev_addr[i] = tms_pci_sifreadw(dev, SIFINC) >> 8; | |
208 | } | |
209 | ||
210 | static unsigned short tms_pci_setnselout_pins(struct net_device *dev) | |
211 | { | |
212 | unsigned short val = 0; | |
213 | struct net_local *tp = dev->priv; | |
214 | struct card_info *cardinfo = tp->tmspriv; | |
215 | ||
216 | if(tp->DataRate == SPEED_4) | |
217 | val |= cardinfo->nselout[0]; /* Set 4Mbps */ | |
218 | else | |
219 | val |= cardinfo->nselout[1]; /* Set 16Mbps */ | |
220 | return val; | |
221 | } | |
222 | ||
223 | static void __devexit tms_pci_detach (struct pci_dev *pdev) | |
224 | { | |
225 | struct net_device *dev = pci_get_drvdata(pdev); | |
226 | ||
227 | if (!dev) | |
228 | BUG(); | |
229 | unregister_netdev(dev); | |
230 | release_region(dev->base_addr, TMS_PCI_IO_EXTENT); | |
231 | free_irq(dev->irq, dev); | |
232 | tmsdev_term(dev); | |
233 | free_netdev(dev); | |
234 | pci_set_drvdata(pdev, NULL); | |
235 | } | |
236 | ||
237 | static struct pci_driver tms_pci_driver = { | |
238 | .name = "tmspci", | |
239 | .id_table = tmspci_pci_tbl, | |
240 | .probe = tms_pci_attach, | |
241 | .remove = __devexit_p(tms_pci_detach), | |
242 | }; | |
243 | ||
244 | static int __init tms_pci_init (void) | |
245 | { | |
246 | return pci_register_driver(&tms_pci_driver); | |
247 | } | |
248 | ||
249 | static void __exit tms_pci_rmmod (void) | |
250 | { | |
251 | pci_unregister_driver (&tms_pci_driver); | |
252 | } | |
253 | ||
254 | module_init(tms_pci_init); | |
255 | module_exit(tms_pci_rmmod); | |
256 |