1/*
2 *  proteon.c: A network driver for Proteon ISA token ring cards.
3 *
4 *  Based on tmspci written 1999 by Adam Fritzler
5 *
6 *  Written 2003 by Jochen Friedrich
7 *
8 *  This software may be used and distributed according to the terms
9 *  of the GNU General Public License, incorporated herein by reference.
10 *
11 *  This driver module supports the following cards:
12 *	- Proteon 1392, 1392+
13 *
14 *  Maintainer(s):
15 *    AF        Adam Fritzler
16 *    JF	Jochen Friedrich	jochen@scram.de
17 *
18 *  Modification History:
19 *	02-Jan-03	JF	Created
20 *
21 */
22static const char version[] = "proteon.c: v1.00 02/01/2003 by Jochen Friedrich\n";
23
24#include <linux/module.h>
25#include <linux/kernel.h>
26#include <linux/delay.h>
27#include <linux/errno.h>
28#include <linux/pci.h>
29#include <linux/init.h>
30#include <linux/netdevice.h>
31#include <linux/trdevice.h>
32#include <linux/platform_device.h>
33
34#include <asm/io.h>
35#include <asm/irq.h>
36#include <asm/pci.h>
37#include <asm/dma.h>
38
39#include "tms380tr.h"
40
41#define PROTEON_IO_EXTENT 32
42
43/* A zero-terminated list of I/O addresses to be probed. */
44static unsigned int portlist[] __initdata = {
45	0x0A20, 0x0E20, 0x1A20, 0x1E20, 0x2A20, 0x2E20, 0x3A20, 0x3E20,// Prot.
46	0x4A20, 0x4E20, 0x5A20, 0x5E20, 0x6A20, 0x6E20, 0x7A20, 0x7E20,// Prot.
47	0x8A20, 0x8E20, 0x9A20, 0x9E20, 0xAA20, 0xAE20, 0xBA20, 0xBE20,// Prot.
48	0xCA20, 0xCE20, 0xDA20, 0xDE20, 0xEA20, 0xEE20, 0xFA20, 0xFE20,// Prot.
49	0
50};
51
52/* A zero-terminated list of IRQs to be probed. */
53static unsigned short irqlist[] = {
54	7, 6, 5, 4, 3, 12, 11, 10, 9,
55	0
56};
57
58/* A zero-terminated list of DMAs to be probed. */
59static int dmalist[] __initdata = {
60	5, 6, 7,
61	0
62};
63
64static char cardname[] = "Proteon 1392\0";
65static u64 dma_mask = ISA_MAX_ADDRESS;
66static int proteon_open(struct net_device *dev);
67static void proteon_read_eeprom(struct net_device *dev);
68static unsigned short proteon_setnselout_pins(struct net_device *dev);
69
70static unsigned short proteon_sifreadb(struct net_device *dev, unsigned short reg)
71{
72	return inb(dev->base_addr + reg);
73}
74
75static unsigned short proteon_sifreadw(struct net_device *dev, unsigned short reg)
76{
77	return inw(dev->base_addr + reg);
78}
79
80static void proteon_sifwriteb(struct net_device *dev, unsigned short val, unsigned short reg)
81{
82	outb(val, dev->base_addr + reg);
83}
84
85static void proteon_sifwritew(struct net_device *dev, unsigned short val, unsigned short reg)
86{
87	outw(val, dev->base_addr + reg);
88}
89
90static int __init proteon_probe1(struct net_device *dev, int ioaddr)
91{
92	unsigned char chk1, chk2;
93	int i;
94
95	if (!request_region(ioaddr, PROTEON_IO_EXTENT, cardname))
96		return -ENODEV;
97
98
99	chk1 = inb(ioaddr + 0x1f);      /* Get Proteon ID reg 1 */
100	if (chk1 != 0x1f)
101		goto nodev;
102
103	chk1 = inb(ioaddr + 0x1e) & 0x07;       /* Get Proteon ID reg 0 */
104	for (i=0; i<16; i++) {
105		chk2 = inb(ioaddr + 0x1e) & 0x07;
106		if (((chk1 + 1) & 0x07) != chk2)
107			goto nodev;
108		chk1 = chk2;
109	}
110
111	dev->base_addr = ioaddr;
112	return 0;
113nodev:
114	release_region(ioaddr, PROTEON_IO_EXTENT);
115	return -ENODEV;
116}
117
118static struct net_device_ops proteon_netdev_ops __read_mostly;
119
120static int __init setup_card(struct net_device *dev, struct device *pdev)
121{
122	struct net_local *tp;
123        static int versionprinted;
124	const unsigned *port;
125	int j,err = 0;
126
127	if (!dev)
128		return -ENOMEM;
129
130	if (dev->base_addr)	/* probe specific location */
131		err = proteon_probe1(dev, dev->base_addr);
132	else {
133		for (port = portlist; *port; port++) {
134			err = proteon_probe1(dev, *port);
135			if (!err)
136				break;
137		}
138	}
139	if (err)
140		goto out5;
141
142	/* At this point we have found a valid card. */
143
144	if (versionprinted++ == 0)
145		printk(KERN_DEBUG "%s", version);
146
147	err = -EIO;
148	pdev->dma_mask = &dma_mask;
149	if (tmsdev_init(dev, pdev))
150		goto out4;
151
152	dev->base_addr &= ~3;
153
154	proteon_read_eeprom(dev);
155
156	printk(KERN_DEBUG "proteon.c:    Ring Station Address: %pM\n",
157	       dev->dev_addr);
158
159	tp = netdev_priv(dev);
160	tp->setnselout = proteon_setnselout_pins;
161
162	tp->sifreadb = proteon_sifreadb;
163	tp->sifreadw = proteon_sifreadw;
164	tp->sifwriteb = proteon_sifwriteb;
165	tp->sifwritew = proteon_sifwritew;
166
167	memcpy(tp->ProductID, cardname, PROD_ID_SIZE + 1);
168
169	tp->tmspriv = NULL;
170
171	dev->netdev_ops = &proteon_netdev_ops;
172
173	if (dev->irq == 0)
174	{
175		for(j = 0; irqlist[j] != 0; j++)
176		{
177			dev->irq = irqlist[j];
178			if (!request_irq(dev->irq, tms380tr_interrupt, 0,
179				cardname, dev))
180				break;
181                }
182
183                if(irqlist[j] == 0)
184                {
185                        printk(KERN_INFO "proteon.c: AutoSelect no IRQ available\n");
186			goto out3;
187		}
188	}
189	else
190	{
191		for(j = 0; irqlist[j] != 0; j++)
192			if (irqlist[j] == dev->irq)
193				break;
194		if (irqlist[j] == 0)
195		{
196			printk(KERN_INFO "proteon.c: Illegal IRQ %d specified\n",
197				dev->irq);
198			goto out3;
199		}
200		if (request_irq(dev->irq, tms380tr_interrupt, 0,
201			cardname, dev))
202		{
203                        printk(KERN_INFO "proteon.c: Selected IRQ %d not available\n",
204				dev->irq);
205			goto out3;
206		}
207	}
208
209	if (dev->dma == 0)
210	{
211		for(j = 0; dmalist[j] != 0; j++)
212		{
213			dev->dma = dmalist[j];
214                        if (!request_dma(dev->dma, cardname))
215				break;
216		}
217
218		if(dmalist[j] == 0)
219		{
220			printk(KERN_INFO "proteon.c: AutoSelect no DMA available\n");
221			goto out2;
222		}
223	}
224	else
225	{
226		for(j = 0; dmalist[j] != 0; j++)
227			if (dmalist[j] == dev->dma)
228				break;
229		if (dmalist[j] == 0)
230		{
231                        printk(KERN_INFO "proteon.c: Illegal DMA %d specified\n",
232				dev->dma);
233			goto out2;
234		}
235		if (request_dma(dev->dma, cardname))
236		{
237                        printk(KERN_INFO "proteon.c: Selected DMA %d not available\n",
238				dev->dma);
239			goto out2;
240		}
241	}
242
243	err = register_netdev(dev);
244	if (err)
245		goto out;
246
247	printk(KERN_DEBUG "%s:    IO: %#4lx  IRQ: %d  DMA: %d\n",
248	       dev->name, dev->base_addr, dev->irq, dev->dma);
249
250	return 0;
251out:
252	free_dma(dev->dma);
253out2:
254	free_irq(dev->irq, dev);
255out3:
256	tmsdev_term(dev);
257out4:
258	release_region(dev->base_addr, PROTEON_IO_EXTENT);
259out5:
260	return err;
261}
262
263/*
264 * Reads MAC address from adapter RAM, which should've read it from
265 * the onboard ROM.
266 *
267 * Calling this on a board that does not support it can be a very
268 * dangerous thing.  The Madge board, for instance, will lock your
269 * machine hard when this is called.  Luckily, its supported in a
270 * separate driver.  --ASF
271 */
272static void proteon_read_eeprom(struct net_device *dev)
273{
274	int i;
275
276	/* Address: 0000:0000 */
277	proteon_sifwritew(dev, 0, SIFADX);
278	proteon_sifwritew(dev, 0, SIFADR);
279
280	/* Read six byte MAC address data */
281	dev->addr_len = 6;
282	for(i = 0; i < 6; i++)
283		dev->dev_addr[i] = proteon_sifreadw(dev, SIFINC) >> 8;
284}
285
286static unsigned short proteon_setnselout_pins(struct net_device *dev)
287{
288	return 0;
289}
290
291static int proteon_open(struct net_device *dev)
292{
293	struct net_local *tp = netdev_priv(dev);
294	unsigned short val = 0;
295	int i;
296
297	/* Proteon reset sequence */
298	outb(0, dev->base_addr + 0x11);
299	mdelay(20);
300	outb(0x04, dev->base_addr + 0x11);
301	mdelay(20);
302	outb(0, dev->base_addr + 0x11);
303	mdelay(100);
304
305	/* set control/status reg */
306	val = inb(dev->base_addr + 0x11);
307	val |= 0x78;
308	val &= 0xf9;
309	if(tp->DataRate == SPEED_4)
310		val |= 0x20;
311	else
312		val &= ~0x20;
313
314	outb(val, dev->base_addr + 0x11);
315	outb(0xff, dev->base_addr + 0x12);
316	for(i = 0; irqlist[i] != 0; i++)
317	{
318		if(irqlist[i] == dev->irq)
319			break;
320	}
321	val = i;
322	i = (7 - dev->dma) << 4;
323	val |= i;
324	outb(val, dev->base_addr + 0x13);
325
326	return tms380tr_open(dev);
327}
328
329#define ISATR_MAX_ADAPTERS 3
330
331static int io[ISATR_MAX_ADAPTERS];
332static int irq[ISATR_MAX_ADAPTERS];
333static int dma[ISATR_MAX_ADAPTERS];
334
335MODULE_LICENSE("GPL");
336
337module_param_array(io, int, NULL, 0);
338module_param_array(irq, int, NULL, 0);
339module_param_array(dma, int, NULL, 0);
340
341static struct platform_device *proteon_dev[ISATR_MAX_ADAPTERS];
342
343static struct platform_driver proteon_driver = {
344	.driver		= {
345		.name	= "proteon",
346	},
347};
348
349static int __init proteon_init(void)
350{
351	struct net_device *dev;
352	struct platform_device *pdev;
353	int i, num = 0, err = 0;
354
355	proteon_netdev_ops = tms380tr_netdev_ops;
356	proteon_netdev_ops.ndo_open = proteon_open;
357	proteon_netdev_ops.ndo_stop = tms380tr_close;
358
359	err = platform_driver_register(&proteon_driver);
360	if (err)
361		return err;
362
363	for (i = 0; i < ISATR_MAX_ADAPTERS ; i++) {
364		dev = alloc_trdev(sizeof(struct net_local));
365		if (!dev)
366			continue;
367
368		dev->base_addr = io[i];
369		dev->irq = irq[i];
370		dev->dma = dma[i];
371		pdev = platform_device_register_simple("proteon",
372			i, NULL, 0);
373		if (IS_ERR(pdev)) {
374			free_netdev(dev);
375			continue;
376		}
377		err = setup_card(dev, &pdev->dev);
378		if (!err) {
379			proteon_dev[i] = pdev;
380			platform_set_drvdata(pdev, dev);
381			++num;
382		} else {
383			platform_device_unregister(pdev);
384			free_netdev(dev);
385		}
386	}
387
388	printk(KERN_NOTICE "proteon.c: %d cards found.\n", num);
389	/* Probe for cards. */
390	if (num == 0) {
391		printk(KERN_NOTICE "proteon.c: No cards found.\n");
392		platform_driver_unregister(&proteon_driver);
393		return -ENODEV;
394	}
395	return 0;
396}
397
398static void __exit proteon_cleanup(void)
399{
400	struct net_device *dev;
401	int i;
402
403	for (i = 0; i < ISATR_MAX_ADAPTERS ; i++) {
404		struct platform_device *pdev = proteon_dev[i];
405
406		if (!pdev)
407			continue;
408		dev = platform_get_drvdata(pdev);
409		unregister_netdev(dev);
410		release_region(dev->base_addr, PROTEON_IO_EXTENT);
411		free_irq(dev->irq, dev);
412		free_dma(dev->dma);
413		tmsdev_term(dev);
414		free_netdev(dev);
415		platform_set_drvdata(pdev, NULL);
416		platform_device_unregister(pdev);
417	}
418	platform_driver_unregister(&proteon_driver);
419}
420
421module_init(proteon_init);
422module_exit(proteon_cleanup);
423