xref: /OK3568_Linux_fs/kernel/drivers/net/sb1000.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /* sb1000.c: A General Instruments SB1000 driver for linux. */
3*4882a593Smuzhiyun /*
4*4882a593Smuzhiyun 	Written 1998 by Franco Venturi.
5*4882a593Smuzhiyun 
6*4882a593Smuzhiyun 	Copyright 1998 by Franco Venturi.
7*4882a593Smuzhiyun 	Copyright 1994,1995 by Donald Becker.
8*4882a593Smuzhiyun 	Copyright 1993 United States Government as represented by the
9*4882a593Smuzhiyun 	Director, National Security Agency.
10*4882a593Smuzhiyun 
11*4882a593Smuzhiyun 	This driver is for the General Instruments SB1000 (internal SURFboard)
12*4882a593Smuzhiyun 
13*4882a593Smuzhiyun 	The author may be reached as fventuri@mediaone.net
14*4882a593Smuzhiyun 
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun 	Changes:
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun 	981115 Steven Hirsch <shirsch@adelphia.net>
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun 	Linus changed the timer interface.  Should work on all recent
21*4882a593Smuzhiyun 	development kernels.
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun 	980608 Steven Hirsch <shirsch@adelphia.net>
24*4882a593Smuzhiyun 
25*4882a593Smuzhiyun 	Small changes to make it work with 2.1.x kernels. Hopefully,
26*4882a593Smuzhiyun 	nothing major will change before official release of Linux 2.2.
27*4882a593Smuzhiyun 
28*4882a593Smuzhiyun 	Merged with 2.2 - Alan Cox
29*4882a593Smuzhiyun */
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun static char version[] = "sb1000.c:v1.1.2 6/01/98 (fventuri@mediaone.net)\n";
32*4882a593Smuzhiyun 
33*4882a593Smuzhiyun #include <linux/module.h>
34*4882a593Smuzhiyun #include <linux/kernel.h>
35*4882a593Smuzhiyun #include <linux/sched.h>
36*4882a593Smuzhiyun #include <linux/string.h>
37*4882a593Smuzhiyun #include <linux/interrupt.h>
38*4882a593Smuzhiyun #include <linux/errno.h>
39*4882a593Smuzhiyun #include <linux/if_cablemodem.h> /* for SIOGCM/SIOSCM stuff */
40*4882a593Smuzhiyun #include <linux/in.h>
41*4882a593Smuzhiyun #include <linux/ioport.h>
42*4882a593Smuzhiyun #include <linux/netdevice.h>
43*4882a593Smuzhiyun #include <linux/if_arp.h>
44*4882a593Smuzhiyun #include <linux/skbuff.h>
45*4882a593Smuzhiyun #include <linux/delay.h>	/* for udelay() */
46*4882a593Smuzhiyun #include <linux/etherdevice.h>
47*4882a593Smuzhiyun #include <linux/pnp.h>
48*4882a593Smuzhiyun #include <linux/init.h>
49*4882a593Smuzhiyun #include <linux/bitops.h>
50*4882a593Smuzhiyun #include <linux/gfp.h>
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun #include <asm/io.h>
53*4882a593Smuzhiyun #include <asm/processor.h>
54*4882a593Smuzhiyun #include <linux/uaccess.h>
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun #ifdef SB1000_DEBUG
57*4882a593Smuzhiyun static int sb1000_debug = SB1000_DEBUG;
58*4882a593Smuzhiyun #else
59*4882a593Smuzhiyun static const int sb1000_debug = 1;
60*4882a593Smuzhiyun #endif
61*4882a593Smuzhiyun 
62*4882a593Smuzhiyun static const int SB1000_IO_EXTENT = 8;
63*4882a593Smuzhiyun /* SB1000 Maximum Receive Unit */
64*4882a593Smuzhiyun static const int SB1000_MRU = 1500; /* octects */
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun #define NPIDS 4
67*4882a593Smuzhiyun struct sb1000_private {
68*4882a593Smuzhiyun 	struct sk_buff *rx_skb[NPIDS];
69*4882a593Smuzhiyun 	short rx_dlen[NPIDS];
70*4882a593Smuzhiyun 	unsigned int rx_frames;
71*4882a593Smuzhiyun 	short rx_error_count;
72*4882a593Smuzhiyun 	short rx_error_dpc_count;
73*4882a593Smuzhiyun 	unsigned char rx_session_id[NPIDS];
74*4882a593Smuzhiyun 	unsigned char rx_frame_id[NPIDS];
75*4882a593Smuzhiyun 	unsigned char rx_pkt_type[NPIDS];
76*4882a593Smuzhiyun };
77*4882a593Smuzhiyun 
78*4882a593Smuzhiyun /* prototypes for Linux interface */
79*4882a593Smuzhiyun extern int sb1000_probe(struct net_device *dev);
80*4882a593Smuzhiyun static int sb1000_open(struct net_device *dev);
81*4882a593Smuzhiyun static int sb1000_dev_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd);
82*4882a593Smuzhiyun static netdev_tx_t sb1000_start_xmit(struct sk_buff *skb,
83*4882a593Smuzhiyun 				     struct net_device *dev);
84*4882a593Smuzhiyun static irqreturn_t sb1000_interrupt(int irq, void *dev_id);
85*4882a593Smuzhiyun static int sb1000_close(struct net_device *dev);
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun /* SB1000 hardware routines to be used during open/configuration phases */
89*4882a593Smuzhiyun static int card_wait_for_busy_clear(const int ioaddr[],
90*4882a593Smuzhiyun 	const char* name);
91*4882a593Smuzhiyun static int card_wait_for_ready(const int ioaddr[], const char* name,
92*4882a593Smuzhiyun 	unsigned char in[]);
93*4882a593Smuzhiyun static int card_send_command(const int ioaddr[], const char* name,
94*4882a593Smuzhiyun 	const unsigned char out[], unsigned char in[]);
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun /* SB1000 hardware routines to be used during frame rx interrupt */
97*4882a593Smuzhiyun static int sb1000_wait_for_ready(const int ioaddr[], const char* name);
98*4882a593Smuzhiyun static int sb1000_wait_for_ready_clear(const int ioaddr[],
99*4882a593Smuzhiyun 	const char* name);
100*4882a593Smuzhiyun static void sb1000_send_command(const int ioaddr[], const char* name,
101*4882a593Smuzhiyun 	const unsigned char out[]);
102*4882a593Smuzhiyun static void sb1000_read_status(const int ioaddr[], unsigned char in[]);
103*4882a593Smuzhiyun static void sb1000_issue_read_command(const int ioaddr[],
104*4882a593Smuzhiyun 	const char* name);
105*4882a593Smuzhiyun 
106*4882a593Smuzhiyun /* SB1000 commands for open/configuration */
107*4882a593Smuzhiyun static int sb1000_reset(const int ioaddr[], const char* name);
108*4882a593Smuzhiyun static int sb1000_check_CRC(const int ioaddr[], const char* name);
109*4882a593Smuzhiyun static inline int sb1000_start_get_set_command(const int ioaddr[],
110*4882a593Smuzhiyun 	const char* name);
111*4882a593Smuzhiyun static int sb1000_end_get_set_command(const int ioaddr[],
112*4882a593Smuzhiyun 	const char* name);
113*4882a593Smuzhiyun static int sb1000_activate(const int ioaddr[], const char* name);
114*4882a593Smuzhiyun static int sb1000_get_firmware_version(const int ioaddr[],
115*4882a593Smuzhiyun 	const char* name, unsigned char version[], int do_end);
116*4882a593Smuzhiyun static int sb1000_get_frequency(const int ioaddr[], const char* name,
117*4882a593Smuzhiyun 	int* frequency);
118*4882a593Smuzhiyun static int sb1000_set_frequency(const int ioaddr[], const char* name,
119*4882a593Smuzhiyun 	int frequency);
120*4882a593Smuzhiyun static int sb1000_get_PIDs(const int ioaddr[], const char* name,
121*4882a593Smuzhiyun 	short PID[]);
122*4882a593Smuzhiyun static int sb1000_set_PIDs(const int ioaddr[], const char* name,
123*4882a593Smuzhiyun 	const short PID[]);
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun /* SB1000 commands for frame rx interrupt */
126*4882a593Smuzhiyun static int sb1000_rx(struct net_device *dev);
127*4882a593Smuzhiyun static void sb1000_error_dpc(struct net_device *dev);
128*4882a593Smuzhiyun 
129*4882a593Smuzhiyun static const struct pnp_device_id sb1000_pnp_ids[] = {
130*4882a593Smuzhiyun 	{ "GIC1000", 0 },
131*4882a593Smuzhiyun 	{ "", 0 }
132*4882a593Smuzhiyun };
133*4882a593Smuzhiyun MODULE_DEVICE_TABLE(pnp, sb1000_pnp_ids);
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun static const struct net_device_ops sb1000_netdev_ops = {
136*4882a593Smuzhiyun 	.ndo_open		= sb1000_open,
137*4882a593Smuzhiyun 	.ndo_start_xmit		= sb1000_start_xmit,
138*4882a593Smuzhiyun 	.ndo_do_ioctl		= sb1000_dev_ioctl,
139*4882a593Smuzhiyun 	.ndo_stop		= sb1000_close,
140*4882a593Smuzhiyun 	.ndo_set_mac_address 	= eth_mac_addr,
141*4882a593Smuzhiyun 	.ndo_validate_addr	= eth_validate_addr,
142*4882a593Smuzhiyun };
143*4882a593Smuzhiyun 
144*4882a593Smuzhiyun static int
sb1000_probe_one(struct pnp_dev * pdev,const struct pnp_device_id * id)145*4882a593Smuzhiyun sb1000_probe_one(struct pnp_dev *pdev, const struct pnp_device_id *id)
146*4882a593Smuzhiyun {
147*4882a593Smuzhiyun 	struct net_device *dev;
148*4882a593Smuzhiyun 	unsigned short ioaddr[2], irq;
149*4882a593Smuzhiyun 	unsigned int serial_number;
150*4882a593Smuzhiyun 	int error = -ENODEV;
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun 	if (pnp_device_attach(pdev) < 0)
153*4882a593Smuzhiyun 		return -ENODEV;
154*4882a593Smuzhiyun 	if (pnp_activate_dev(pdev) < 0)
155*4882a593Smuzhiyun 		goto out_detach;
156*4882a593Smuzhiyun 
157*4882a593Smuzhiyun 	if (!pnp_port_valid(pdev, 0) || !pnp_port_valid(pdev, 1))
158*4882a593Smuzhiyun 		goto out_disable;
159*4882a593Smuzhiyun 	if (!pnp_irq_valid(pdev, 0))
160*4882a593Smuzhiyun 		goto out_disable;
161*4882a593Smuzhiyun 
162*4882a593Smuzhiyun 	serial_number = pdev->card->serial;
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun 	ioaddr[0] = pnp_port_start(pdev, 0);
165*4882a593Smuzhiyun 	ioaddr[1] = pnp_port_start(pdev, 0);
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun 	irq = pnp_irq(pdev, 0);
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun 	if (!request_region(ioaddr[0], 16, "sb1000"))
170*4882a593Smuzhiyun 		goto out_disable;
171*4882a593Smuzhiyun 	if (!request_region(ioaddr[1], 16, "sb1000"))
172*4882a593Smuzhiyun 		goto out_release_region0;
173*4882a593Smuzhiyun 
174*4882a593Smuzhiyun 	dev = alloc_etherdev(sizeof(struct sb1000_private));
175*4882a593Smuzhiyun 	if (!dev) {
176*4882a593Smuzhiyun 		error = -ENOMEM;
177*4882a593Smuzhiyun 		goto out_release_regions;
178*4882a593Smuzhiyun 	}
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun 	dev->base_addr = ioaddr[0];
182*4882a593Smuzhiyun 	/* mem_start holds the second I/O address */
183*4882a593Smuzhiyun 	dev->mem_start = ioaddr[1];
184*4882a593Smuzhiyun 	dev->irq = irq;
185*4882a593Smuzhiyun 
186*4882a593Smuzhiyun 	if (sb1000_debug > 0)
187*4882a593Smuzhiyun 		printk(KERN_NOTICE "%s: sb1000 at (%#3.3lx,%#3.3lx), "
188*4882a593Smuzhiyun 			"S/N %#8.8x, IRQ %d.\n", dev->name, dev->base_addr,
189*4882a593Smuzhiyun 			dev->mem_start, serial_number, dev->irq);
190*4882a593Smuzhiyun 
191*4882a593Smuzhiyun 	/*
192*4882a593Smuzhiyun 	 * The SB1000 is an rx-only cable modem device.  The uplink is a modem
193*4882a593Smuzhiyun 	 * and we do not want to arp on it.
194*4882a593Smuzhiyun 	 */
195*4882a593Smuzhiyun 	dev->flags = IFF_POINTOPOINT|IFF_NOARP;
196*4882a593Smuzhiyun 
197*4882a593Smuzhiyun 	SET_NETDEV_DEV(dev, &pdev->dev);
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun 	if (sb1000_debug > 0)
200*4882a593Smuzhiyun 		printk(KERN_NOTICE "%s", version);
201*4882a593Smuzhiyun 
202*4882a593Smuzhiyun 	dev->netdev_ops	= &sb1000_netdev_ops;
203*4882a593Smuzhiyun 
204*4882a593Smuzhiyun 	/* hardware address is 0:0:serial_number */
205*4882a593Smuzhiyun 	dev->dev_addr[2]	= serial_number >> 24 & 0xff;
206*4882a593Smuzhiyun 	dev->dev_addr[3]	= serial_number >> 16 & 0xff;
207*4882a593Smuzhiyun 	dev->dev_addr[4]	= serial_number >>  8 & 0xff;
208*4882a593Smuzhiyun 	dev->dev_addr[5]	= serial_number >>  0 & 0xff;
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun 	pnp_set_drvdata(pdev, dev);
211*4882a593Smuzhiyun 
212*4882a593Smuzhiyun 	error = register_netdev(dev);
213*4882a593Smuzhiyun 	if (error)
214*4882a593Smuzhiyun 		goto out_free_netdev;
215*4882a593Smuzhiyun 	return 0;
216*4882a593Smuzhiyun 
217*4882a593Smuzhiyun  out_free_netdev:
218*4882a593Smuzhiyun 	free_netdev(dev);
219*4882a593Smuzhiyun  out_release_regions:
220*4882a593Smuzhiyun 	release_region(ioaddr[1], 16);
221*4882a593Smuzhiyun  out_release_region0:
222*4882a593Smuzhiyun 	release_region(ioaddr[0], 16);
223*4882a593Smuzhiyun  out_disable:
224*4882a593Smuzhiyun 	pnp_disable_dev(pdev);
225*4882a593Smuzhiyun  out_detach:
226*4882a593Smuzhiyun 	pnp_device_detach(pdev);
227*4882a593Smuzhiyun 	return error;
228*4882a593Smuzhiyun }
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun static void
sb1000_remove_one(struct pnp_dev * pdev)231*4882a593Smuzhiyun sb1000_remove_one(struct pnp_dev *pdev)
232*4882a593Smuzhiyun {
233*4882a593Smuzhiyun 	struct net_device *dev = pnp_get_drvdata(pdev);
234*4882a593Smuzhiyun 
235*4882a593Smuzhiyun 	unregister_netdev(dev);
236*4882a593Smuzhiyun 	release_region(dev->base_addr, 16);
237*4882a593Smuzhiyun 	release_region(dev->mem_start, 16);
238*4882a593Smuzhiyun 	free_netdev(dev);
239*4882a593Smuzhiyun }
240*4882a593Smuzhiyun 
241*4882a593Smuzhiyun static struct pnp_driver sb1000_driver = {
242*4882a593Smuzhiyun 	.name		= "sb1000",
243*4882a593Smuzhiyun 	.id_table	= sb1000_pnp_ids,
244*4882a593Smuzhiyun 	.probe		= sb1000_probe_one,
245*4882a593Smuzhiyun 	.remove		= sb1000_remove_one,
246*4882a593Smuzhiyun };
247*4882a593Smuzhiyun 
248*4882a593Smuzhiyun 
249*4882a593Smuzhiyun /*
250*4882a593Smuzhiyun  * SB1000 hardware routines to be used during open/configuration phases
251*4882a593Smuzhiyun  */
252*4882a593Smuzhiyun 
253*4882a593Smuzhiyun static const int TimeOutJiffies = (875 * HZ) / 100;
254*4882a593Smuzhiyun 
255*4882a593Smuzhiyun /* Card Wait For Busy Clear (cannot be used during an interrupt) */
256*4882a593Smuzhiyun static int
card_wait_for_busy_clear(const int ioaddr[],const char * name)257*4882a593Smuzhiyun card_wait_for_busy_clear(const int ioaddr[], const char* name)
258*4882a593Smuzhiyun {
259*4882a593Smuzhiyun 	unsigned char a;
260*4882a593Smuzhiyun 	unsigned long timeout;
261*4882a593Smuzhiyun 
262*4882a593Smuzhiyun 	a = inb(ioaddr[0] + 7);
263*4882a593Smuzhiyun 	timeout = jiffies + TimeOutJiffies;
264*4882a593Smuzhiyun 	while (a & 0x80 || a & 0x40) {
265*4882a593Smuzhiyun 		/* a little sleep */
266*4882a593Smuzhiyun 		yield();
267*4882a593Smuzhiyun 
268*4882a593Smuzhiyun 		a = inb(ioaddr[0] + 7);
269*4882a593Smuzhiyun 		if (time_after_eq(jiffies, timeout)) {
270*4882a593Smuzhiyun 			printk(KERN_WARNING "%s: card_wait_for_busy_clear timeout\n",
271*4882a593Smuzhiyun 				name);
272*4882a593Smuzhiyun 			return -ETIME;
273*4882a593Smuzhiyun 		}
274*4882a593Smuzhiyun 	}
275*4882a593Smuzhiyun 
276*4882a593Smuzhiyun 	return 0;
277*4882a593Smuzhiyun }
278*4882a593Smuzhiyun 
279*4882a593Smuzhiyun /* Card Wait For Ready (cannot be used during an interrupt) */
280*4882a593Smuzhiyun static int
card_wait_for_ready(const int ioaddr[],const char * name,unsigned char in[])281*4882a593Smuzhiyun card_wait_for_ready(const int ioaddr[], const char* name, unsigned char in[])
282*4882a593Smuzhiyun {
283*4882a593Smuzhiyun 	unsigned char a;
284*4882a593Smuzhiyun 	unsigned long timeout;
285*4882a593Smuzhiyun 
286*4882a593Smuzhiyun 	a = inb(ioaddr[1] + 6);
287*4882a593Smuzhiyun 	timeout = jiffies + TimeOutJiffies;
288*4882a593Smuzhiyun 	while (a & 0x80 || !(a & 0x40)) {
289*4882a593Smuzhiyun 		/* a little sleep */
290*4882a593Smuzhiyun 		yield();
291*4882a593Smuzhiyun 
292*4882a593Smuzhiyun 		a = inb(ioaddr[1] + 6);
293*4882a593Smuzhiyun 		if (time_after_eq(jiffies, timeout)) {
294*4882a593Smuzhiyun 			printk(KERN_WARNING "%s: card_wait_for_ready timeout\n",
295*4882a593Smuzhiyun 				name);
296*4882a593Smuzhiyun 			return -ETIME;
297*4882a593Smuzhiyun 		}
298*4882a593Smuzhiyun 	}
299*4882a593Smuzhiyun 
300*4882a593Smuzhiyun 	in[1] = inb(ioaddr[0] + 1);
301*4882a593Smuzhiyun 	in[2] = inb(ioaddr[0] + 2);
302*4882a593Smuzhiyun 	in[3] = inb(ioaddr[0] + 3);
303*4882a593Smuzhiyun 	in[4] = inb(ioaddr[0] + 4);
304*4882a593Smuzhiyun 	in[0] = inb(ioaddr[0] + 5);
305*4882a593Smuzhiyun 	in[6] = inb(ioaddr[0] + 6);
306*4882a593Smuzhiyun 	in[5] = inb(ioaddr[1] + 6);
307*4882a593Smuzhiyun 	return 0;
308*4882a593Smuzhiyun }
309*4882a593Smuzhiyun 
310*4882a593Smuzhiyun /* Card Send Command (cannot be used during an interrupt) */
311*4882a593Smuzhiyun static int
card_send_command(const int ioaddr[],const char * name,const unsigned char out[],unsigned char in[])312*4882a593Smuzhiyun card_send_command(const int ioaddr[], const char* name,
313*4882a593Smuzhiyun 	const unsigned char out[], unsigned char in[])
314*4882a593Smuzhiyun {
315*4882a593Smuzhiyun 	int status;
316*4882a593Smuzhiyun 
317*4882a593Smuzhiyun 	if ((status = card_wait_for_busy_clear(ioaddr, name)))
318*4882a593Smuzhiyun 		return status;
319*4882a593Smuzhiyun 	outb(0xa0, ioaddr[0] + 6);
320*4882a593Smuzhiyun 	outb(out[2], ioaddr[0] + 1);
321*4882a593Smuzhiyun 	outb(out[3], ioaddr[0] + 2);
322*4882a593Smuzhiyun 	outb(out[4], ioaddr[0] + 3);
323*4882a593Smuzhiyun 	outb(out[5], ioaddr[0] + 4);
324*4882a593Smuzhiyun 	outb(out[1], ioaddr[0] + 5);
325*4882a593Smuzhiyun 	outb(0xa0, ioaddr[0] + 6);
326*4882a593Smuzhiyun 	outb(out[0], ioaddr[0] + 7);
327*4882a593Smuzhiyun 	if (out[0] != 0x20 && out[0] != 0x30) {
328*4882a593Smuzhiyun 		if ((status = card_wait_for_ready(ioaddr, name, in)))
329*4882a593Smuzhiyun 			return status;
330*4882a593Smuzhiyun 		inb(ioaddr[0] + 7);
331*4882a593Smuzhiyun 		if (sb1000_debug > 3)
332*4882a593Smuzhiyun 			printk(KERN_DEBUG "%s: card_send_command "
333*4882a593Smuzhiyun 				"out: %02x%02x%02x%02x%02x%02x  "
334*4882a593Smuzhiyun 				"in: %02x%02x%02x%02x%02x%02x%02x\n", name,
335*4882a593Smuzhiyun 				out[0], out[1], out[2], out[3], out[4], out[5],
336*4882a593Smuzhiyun 				in[0], in[1], in[2], in[3], in[4], in[5], in[6]);
337*4882a593Smuzhiyun 	} else {
338*4882a593Smuzhiyun 		if (sb1000_debug > 3)
339*4882a593Smuzhiyun 			printk(KERN_DEBUG "%s: card_send_command "
340*4882a593Smuzhiyun 				"out: %02x%02x%02x%02x%02x%02x\n", name,
341*4882a593Smuzhiyun 				out[0], out[1], out[2], out[3], out[4], out[5]);
342*4882a593Smuzhiyun 	}
343*4882a593Smuzhiyun 
344*4882a593Smuzhiyun 	if (out[1] != 0x1b) {
345*4882a593Smuzhiyun 		if (out[0] >= 0x80 && in[0] != (out[1] | 0x80))
346*4882a593Smuzhiyun 			return -EIO;
347*4882a593Smuzhiyun 	}
348*4882a593Smuzhiyun 	return 0;
349*4882a593Smuzhiyun }
350*4882a593Smuzhiyun 
351*4882a593Smuzhiyun 
352*4882a593Smuzhiyun /*
353*4882a593Smuzhiyun  * SB1000 hardware routines to be used during frame rx interrupt
354*4882a593Smuzhiyun  */
355*4882a593Smuzhiyun static const int Sb1000TimeOutJiffies = 7 * HZ;
356*4882a593Smuzhiyun 
357*4882a593Smuzhiyun /* Card Wait For Ready (to be used during frame rx) */
358*4882a593Smuzhiyun static int
sb1000_wait_for_ready(const int ioaddr[],const char * name)359*4882a593Smuzhiyun sb1000_wait_for_ready(const int ioaddr[], const char* name)
360*4882a593Smuzhiyun {
361*4882a593Smuzhiyun 	unsigned long timeout;
362*4882a593Smuzhiyun 
363*4882a593Smuzhiyun 	timeout = jiffies + Sb1000TimeOutJiffies;
364*4882a593Smuzhiyun 	while (inb(ioaddr[1] + 6) & 0x80) {
365*4882a593Smuzhiyun 		if (time_after_eq(jiffies, timeout)) {
366*4882a593Smuzhiyun 			printk(KERN_WARNING "%s: sb1000_wait_for_ready timeout\n",
367*4882a593Smuzhiyun 				name);
368*4882a593Smuzhiyun 			return -ETIME;
369*4882a593Smuzhiyun 		}
370*4882a593Smuzhiyun 	}
371*4882a593Smuzhiyun 	timeout = jiffies + Sb1000TimeOutJiffies;
372*4882a593Smuzhiyun 	while (!(inb(ioaddr[1] + 6) & 0x40)) {
373*4882a593Smuzhiyun 		if (time_after_eq(jiffies, timeout)) {
374*4882a593Smuzhiyun 			printk(KERN_WARNING "%s: sb1000_wait_for_ready timeout\n",
375*4882a593Smuzhiyun 				name);
376*4882a593Smuzhiyun 			return -ETIME;
377*4882a593Smuzhiyun 		}
378*4882a593Smuzhiyun 	}
379*4882a593Smuzhiyun 	inb(ioaddr[0] + 7);
380*4882a593Smuzhiyun 	return 0;
381*4882a593Smuzhiyun }
382*4882a593Smuzhiyun 
383*4882a593Smuzhiyun /* Card Wait For Ready Clear (to be used during frame rx) */
384*4882a593Smuzhiyun static int
sb1000_wait_for_ready_clear(const int ioaddr[],const char * name)385*4882a593Smuzhiyun sb1000_wait_for_ready_clear(const int ioaddr[], const char* name)
386*4882a593Smuzhiyun {
387*4882a593Smuzhiyun 	unsigned long timeout;
388*4882a593Smuzhiyun 
389*4882a593Smuzhiyun 	timeout = jiffies + Sb1000TimeOutJiffies;
390*4882a593Smuzhiyun 	while (inb(ioaddr[1] + 6) & 0x80) {
391*4882a593Smuzhiyun 		if (time_after_eq(jiffies, timeout)) {
392*4882a593Smuzhiyun 			printk(KERN_WARNING "%s: sb1000_wait_for_ready_clear timeout\n",
393*4882a593Smuzhiyun 				name);
394*4882a593Smuzhiyun 			return -ETIME;
395*4882a593Smuzhiyun 		}
396*4882a593Smuzhiyun 	}
397*4882a593Smuzhiyun 	timeout = jiffies + Sb1000TimeOutJiffies;
398*4882a593Smuzhiyun 	while (inb(ioaddr[1] + 6) & 0x40) {
399*4882a593Smuzhiyun 		if (time_after_eq(jiffies, timeout)) {
400*4882a593Smuzhiyun 			printk(KERN_WARNING "%s: sb1000_wait_for_ready_clear timeout\n",
401*4882a593Smuzhiyun 				name);
402*4882a593Smuzhiyun 			return -ETIME;
403*4882a593Smuzhiyun 		}
404*4882a593Smuzhiyun 	}
405*4882a593Smuzhiyun 	return 0;
406*4882a593Smuzhiyun }
407*4882a593Smuzhiyun 
408*4882a593Smuzhiyun /* Card Send Command (to be used during frame rx) */
409*4882a593Smuzhiyun static void
sb1000_send_command(const int ioaddr[],const char * name,const unsigned char out[])410*4882a593Smuzhiyun sb1000_send_command(const int ioaddr[], const char* name,
411*4882a593Smuzhiyun 	const unsigned char out[])
412*4882a593Smuzhiyun {
413*4882a593Smuzhiyun 	outb(out[2], ioaddr[0] + 1);
414*4882a593Smuzhiyun 	outb(out[3], ioaddr[0] + 2);
415*4882a593Smuzhiyun 	outb(out[4], ioaddr[0] + 3);
416*4882a593Smuzhiyun 	outb(out[5], ioaddr[0] + 4);
417*4882a593Smuzhiyun 	outb(out[1], ioaddr[0] + 5);
418*4882a593Smuzhiyun 	outb(out[0], ioaddr[0] + 7);
419*4882a593Smuzhiyun 	if (sb1000_debug > 3)
420*4882a593Smuzhiyun 		printk(KERN_DEBUG "%s: sb1000_send_command out: %02x%02x%02x%02x"
421*4882a593Smuzhiyun 			"%02x%02x\n", name, out[0], out[1], out[2], out[3], out[4], out[5]);
422*4882a593Smuzhiyun }
423*4882a593Smuzhiyun 
424*4882a593Smuzhiyun /* Card Read Status (to be used during frame rx) */
425*4882a593Smuzhiyun static void
sb1000_read_status(const int ioaddr[],unsigned char in[])426*4882a593Smuzhiyun sb1000_read_status(const int ioaddr[], unsigned char in[])
427*4882a593Smuzhiyun {
428*4882a593Smuzhiyun 	in[1] = inb(ioaddr[0] + 1);
429*4882a593Smuzhiyun 	in[2] = inb(ioaddr[0] + 2);
430*4882a593Smuzhiyun 	in[3] = inb(ioaddr[0] + 3);
431*4882a593Smuzhiyun 	in[4] = inb(ioaddr[0] + 4);
432*4882a593Smuzhiyun 	in[0] = inb(ioaddr[0] + 5);
433*4882a593Smuzhiyun }
434*4882a593Smuzhiyun 
435*4882a593Smuzhiyun /* Issue Read Command (to be used during frame rx) */
436*4882a593Smuzhiyun static void
sb1000_issue_read_command(const int ioaddr[],const char * name)437*4882a593Smuzhiyun sb1000_issue_read_command(const int ioaddr[], const char* name)
438*4882a593Smuzhiyun {
439*4882a593Smuzhiyun 	static const unsigned char Command0[6] = {0x20, 0x00, 0x00, 0x01, 0x00, 0x00};
440*4882a593Smuzhiyun 
441*4882a593Smuzhiyun 	sb1000_wait_for_ready_clear(ioaddr, name);
442*4882a593Smuzhiyun 	outb(0xa0, ioaddr[0] + 6);
443*4882a593Smuzhiyun 	sb1000_send_command(ioaddr, name, Command0);
444*4882a593Smuzhiyun }
445*4882a593Smuzhiyun 
446*4882a593Smuzhiyun 
447*4882a593Smuzhiyun /*
448*4882a593Smuzhiyun  * SB1000 commands for open/configuration
449*4882a593Smuzhiyun  */
450*4882a593Smuzhiyun /* reset SB1000 card */
451*4882a593Smuzhiyun static int
sb1000_reset(const int ioaddr[],const char * name)452*4882a593Smuzhiyun sb1000_reset(const int ioaddr[], const char* name)
453*4882a593Smuzhiyun {
454*4882a593Smuzhiyun 	static const unsigned char Command0[6] = {0x80, 0x16, 0x00, 0x00, 0x00, 0x00};
455*4882a593Smuzhiyun 
456*4882a593Smuzhiyun 	unsigned char st[7];
457*4882a593Smuzhiyun 	int port, status;
458*4882a593Smuzhiyun 
459*4882a593Smuzhiyun 	port = ioaddr[1] + 6;
460*4882a593Smuzhiyun 	outb(0x4, port);
461*4882a593Smuzhiyun 	inb(port);
462*4882a593Smuzhiyun 	udelay(1000);
463*4882a593Smuzhiyun 	outb(0x0, port);
464*4882a593Smuzhiyun 	inb(port);
465*4882a593Smuzhiyun 	ssleep(1);
466*4882a593Smuzhiyun 	outb(0x4, port);
467*4882a593Smuzhiyun 	inb(port);
468*4882a593Smuzhiyun 	udelay(1000);
469*4882a593Smuzhiyun 	outb(0x0, port);
470*4882a593Smuzhiyun 	inb(port);
471*4882a593Smuzhiyun 	udelay(0);
472*4882a593Smuzhiyun 
473*4882a593Smuzhiyun 	if ((status = card_send_command(ioaddr, name, Command0, st)))
474*4882a593Smuzhiyun 		return status;
475*4882a593Smuzhiyun 	if (st[3] != 0xf0)
476*4882a593Smuzhiyun 		return -EIO;
477*4882a593Smuzhiyun 	return 0;
478*4882a593Smuzhiyun }
479*4882a593Smuzhiyun 
480*4882a593Smuzhiyun /* check SB1000 firmware CRC */
481*4882a593Smuzhiyun static int
sb1000_check_CRC(const int ioaddr[],const char * name)482*4882a593Smuzhiyun sb1000_check_CRC(const int ioaddr[], const char* name)
483*4882a593Smuzhiyun {
484*4882a593Smuzhiyun 	static const unsigned char Command0[6] = {0x80, 0x1f, 0x00, 0x00, 0x00, 0x00};
485*4882a593Smuzhiyun 
486*4882a593Smuzhiyun 	unsigned char st[7];
487*4882a593Smuzhiyun 	int status;
488*4882a593Smuzhiyun 
489*4882a593Smuzhiyun 	/* check CRC */
490*4882a593Smuzhiyun 	if ((status = card_send_command(ioaddr, name, Command0, st)))
491*4882a593Smuzhiyun 		return status;
492*4882a593Smuzhiyun 	if (st[1] != st[3] || st[2] != st[4])
493*4882a593Smuzhiyun 		return -EIO;
494*4882a593Smuzhiyun 	return 0;
495*4882a593Smuzhiyun }
496*4882a593Smuzhiyun 
497*4882a593Smuzhiyun static inline int
sb1000_start_get_set_command(const int ioaddr[],const char * name)498*4882a593Smuzhiyun sb1000_start_get_set_command(const int ioaddr[], const char* name)
499*4882a593Smuzhiyun {
500*4882a593Smuzhiyun 	static const unsigned char Command0[6] = {0x80, 0x1b, 0x00, 0x00, 0x00, 0x00};
501*4882a593Smuzhiyun 
502*4882a593Smuzhiyun 	unsigned char st[7];
503*4882a593Smuzhiyun 
504*4882a593Smuzhiyun 	return card_send_command(ioaddr, name, Command0, st);
505*4882a593Smuzhiyun }
506*4882a593Smuzhiyun 
507*4882a593Smuzhiyun static int
sb1000_end_get_set_command(const int ioaddr[],const char * name)508*4882a593Smuzhiyun sb1000_end_get_set_command(const int ioaddr[], const char* name)
509*4882a593Smuzhiyun {
510*4882a593Smuzhiyun 	static const unsigned char Command0[6] = {0x80, 0x1b, 0x02, 0x00, 0x00, 0x00};
511*4882a593Smuzhiyun 	static const unsigned char Command1[6] = {0x20, 0x00, 0x00, 0x00, 0x00, 0x00};
512*4882a593Smuzhiyun 
513*4882a593Smuzhiyun 	unsigned char st[7];
514*4882a593Smuzhiyun 	int status;
515*4882a593Smuzhiyun 
516*4882a593Smuzhiyun 	if ((status = card_send_command(ioaddr, name, Command0, st)))
517*4882a593Smuzhiyun 		return status;
518*4882a593Smuzhiyun 	return card_send_command(ioaddr, name, Command1, st);
519*4882a593Smuzhiyun }
520*4882a593Smuzhiyun 
521*4882a593Smuzhiyun static int
sb1000_activate(const int ioaddr[],const char * name)522*4882a593Smuzhiyun sb1000_activate(const int ioaddr[], const char* name)
523*4882a593Smuzhiyun {
524*4882a593Smuzhiyun 	static const unsigned char Command0[6] = {0x80, 0x11, 0x00, 0x00, 0x00, 0x00};
525*4882a593Smuzhiyun 	static const unsigned char Command1[6] = {0x80, 0x16, 0x00, 0x00, 0x00, 0x00};
526*4882a593Smuzhiyun 
527*4882a593Smuzhiyun 	unsigned char st[7];
528*4882a593Smuzhiyun 	int status;
529*4882a593Smuzhiyun 
530*4882a593Smuzhiyun 	ssleep(1);
531*4882a593Smuzhiyun 	status = card_send_command(ioaddr, name, Command0, st);
532*4882a593Smuzhiyun 	if (status)
533*4882a593Smuzhiyun 		return status;
534*4882a593Smuzhiyun 	status = card_send_command(ioaddr, name, Command1, st);
535*4882a593Smuzhiyun 	if (status)
536*4882a593Smuzhiyun 		return status;
537*4882a593Smuzhiyun 	if (st[3] != 0xf1) {
538*4882a593Smuzhiyun 		status = sb1000_start_get_set_command(ioaddr, name);
539*4882a593Smuzhiyun 		if (status)
540*4882a593Smuzhiyun 			return status;
541*4882a593Smuzhiyun 		return -EIO;
542*4882a593Smuzhiyun 	}
543*4882a593Smuzhiyun 	udelay(1000);
544*4882a593Smuzhiyun 	return sb1000_start_get_set_command(ioaddr, name);
545*4882a593Smuzhiyun }
546*4882a593Smuzhiyun 
547*4882a593Smuzhiyun /* get SB1000 firmware version */
548*4882a593Smuzhiyun static int
sb1000_get_firmware_version(const int ioaddr[],const char * name,unsigned char version[],int do_end)549*4882a593Smuzhiyun sb1000_get_firmware_version(const int ioaddr[], const char* name,
550*4882a593Smuzhiyun 	unsigned char version[], int do_end)
551*4882a593Smuzhiyun {
552*4882a593Smuzhiyun 	static const unsigned char Command0[6] = {0x80, 0x23, 0x00, 0x00, 0x00, 0x00};
553*4882a593Smuzhiyun 
554*4882a593Smuzhiyun 	unsigned char st[7];
555*4882a593Smuzhiyun 	int status;
556*4882a593Smuzhiyun 
557*4882a593Smuzhiyun 	if ((status = sb1000_start_get_set_command(ioaddr, name)))
558*4882a593Smuzhiyun 		return status;
559*4882a593Smuzhiyun 	if ((status = card_send_command(ioaddr, name, Command0, st)))
560*4882a593Smuzhiyun 		return status;
561*4882a593Smuzhiyun 	if (st[0] != 0xa3)
562*4882a593Smuzhiyun 		return -EIO;
563*4882a593Smuzhiyun 	version[0] = st[1];
564*4882a593Smuzhiyun 	version[1] = st[2];
565*4882a593Smuzhiyun 	if (do_end)
566*4882a593Smuzhiyun 		return sb1000_end_get_set_command(ioaddr, name);
567*4882a593Smuzhiyun 	else
568*4882a593Smuzhiyun 		return 0;
569*4882a593Smuzhiyun }
570*4882a593Smuzhiyun 
571*4882a593Smuzhiyun /* get SB1000 frequency */
572*4882a593Smuzhiyun static int
sb1000_get_frequency(const int ioaddr[],const char * name,int * frequency)573*4882a593Smuzhiyun sb1000_get_frequency(const int ioaddr[], const char* name, int* frequency)
574*4882a593Smuzhiyun {
575*4882a593Smuzhiyun 	static const unsigned char Command0[6] = {0x80, 0x44, 0x00, 0x00, 0x00, 0x00};
576*4882a593Smuzhiyun 
577*4882a593Smuzhiyun 	unsigned char st[7];
578*4882a593Smuzhiyun 	int status;
579*4882a593Smuzhiyun 
580*4882a593Smuzhiyun 	udelay(1000);
581*4882a593Smuzhiyun 	if ((status = sb1000_start_get_set_command(ioaddr, name)))
582*4882a593Smuzhiyun 		return status;
583*4882a593Smuzhiyun 	if ((status = card_send_command(ioaddr, name, Command0, st)))
584*4882a593Smuzhiyun 		return status;
585*4882a593Smuzhiyun 	*frequency = ((st[1] << 8 | st[2]) << 8 | st[3]) << 8 | st[4];
586*4882a593Smuzhiyun 	return sb1000_end_get_set_command(ioaddr, name);
587*4882a593Smuzhiyun }
588*4882a593Smuzhiyun 
589*4882a593Smuzhiyun /* set SB1000 frequency */
590*4882a593Smuzhiyun static int
sb1000_set_frequency(const int ioaddr[],const char * name,int frequency)591*4882a593Smuzhiyun sb1000_set_frequency(const int ioaddr[], const char* name, int frequency)
592*4882a593Smuzhiyun {
593*4882a593Smuzhiyun 	unsigned char st[7];
594*4882a593Smuzhiyun 	int status;
595*4882a593Smuzhiyun 	unsigned char Command0[6] = {0x80, 0x29, 0x00, 0x00, 0x00, 0x00};
596*4882a593Smuzhiyun 
597*4882a593Smuzhiyun 	const int FrequencyLowerLimit = 57000;
598*4882a593Smuzhiyun 	const int FrequencyUpperLimit = 804000;
599*4882a593Smuzhiyun 
600*4882a593Smuzhiyun 	if (frequency < FrequencyLowerLimit || frequency > FrequencyUpperLimit) {
601*4882a593Smuzhiyun 		printk(KERN_ERR "%s: frequency chosen (%d kHz) is not in the range "
602*4882a593Smuzhiyun 			"[%d,%d] kHz\n", name, frequency, FrequencyLowerLimit,
603*4882a593Smuzhiyun 			FrequencyUpperLimit);
604*4882a593Smuzhiyun 		return -EINVAL;
605*4882a593Smuzhiyun 	}
606*4882a593Smuzhiyun 	udelay(1000);
607*4882a593Smuzhiyun 	if ((status = sb1000_start_get_set_command(ioaddr, name)))
608*4882a593Smuzhiyun 		return status;
609*4882a593Smuzhiyun 	Command0[5] = frequency & 0xff;
610*4882a593Smuzhiyun 	frequency >>= 8;
611*4882a593Smuzhiyun 	Command0[4] = frequency & 0xff;
612*4882a593Smuzhiyun 	frequency >>= 8;
613*4882a593Smuzhiyun 	Command0[3] = frequency & 0xff;
614*4882a593Smuzhiyun 	frequency >>= 8;
615*4882a593Smuzhiyun 	Command0[2] = frequency & 0xff;
616*4882a593Smuzhiyun 	return card_send_command(ioaddr, name, Command0, st);
617*4882a593Smuzhiyun }
618*4882a593Smuzhiyun 
619*4882a593Smuzhiyun /* get SB1000 PIDs */
620*4882a593Smuzhiyun static int
sb1000_get_PIDs(const int ioaddr[],const char * name,short PID[])621*4882a593Smuzhiyun sb1000_get_PIDs(const int ioaddr[], const char* name, short PID[])
622*4882a593Smuzhiyun {
623*4882a593Smuzhiyun 	static const unsigned char Command0[6] = {0x80, 0x40, 0x00, 0x00, 0x00, 0x00};
624*4882a593Smuzhiyun 	static const unsigned char Command1[6] = {0x80, 0x41, 0x00, 0x00, 0x00, 0x00};
625*4882a593Smuzhiyun 	static const unsigned char Command2[6] = {0x80, 0x42, 0x00, 0x00, 0x00, 0x00};
626*4882a593Smuzhiyun 	static const unsigned char Command3[6] = {0x80, 0x43, 0x00, 0x00, 0x00, 0x00};
627*4882a593Smuzhiyun 
628*4882a593Smuzhiyun 	unsigned char st[7];
629*4882a593Smuzhiyun 	int status;
630*4882a593Smuzhiyun 
631*4882a593Smuzhiyun 	udelay(1000);
632*4882a593Smuzhiyun 	if ((status = sb1000_start_get_set_command(ioaddr, name)))
633*4882a593Smuzhiyun 		return status;
634*4882a593Smuzhiyun 
635*4882a593Smuzhiyun 	if ((status = card_send_command(ioaddr, name, Command0, st)))
636*4882a593Smuzhiyun 		return status;
637*4882a593Smuzhiyun 	PID[0] = st[1] << 8 | st[2];
638*4882a593Smuzhiyun 
639*4882a593Smuzhiyun 	if ((status = card_send_command(ioaddr, name, Command1, st)))
640*4882a593Smuzhiyun 		return status;
641*4882a593Smuzhiyun 	PID[1] = st[1] << 8 | st[2];
642*4882a593Smuzhiyun 
643*4882a593Smuzhiyun 	if ((status = card_send_command(ioaddr, name, Command2, st)))
644*4882a593Smuzhiyun 		return status;
645*4882a593Smuzhiyun 	PID[2] = st[1] << 8 | st[2];
646*4882a593Smuzhiyun 
647*4882a593Smuzhiyun 	if ((status = card_send_command(ioaddr, name, Command3, st)))
648*4882a593Smuzhiyun 		return status;
649*4882a593Smuzhiyun 	PID[3] = st[1] << 8 | st[2];
650*4882a593Smuzhiyun 
651*4882a593Smuzhiyun 	return sb1000_end_get_set_command(ioaddr, name);
652*4882a593Smuzhiyun }
653*4882a593Smuzhiyun 
654*4882a593Smuzhiyun /* set SB1000 PIDs */
655*4882a593Smuzhiyun static int
sb1000_set_PIDs(const int ioaddr[],const char * name,const short PID[])656*4882a593Smuzhiyun sb1000_set_PIDs(const int ioaddr[], const char* name, const short PID[])
657*4882a593Smuzhiyun {
658*4882a593Smuzhiyun 	static const unsigned char Command4[6] = {0x80, 0x2e, 0x00, 0x00, 0x00, 0x00};
659*4882a593Smuzhiyun 
660*4882a593Smuzhiyun 	unsigned char st[7];
661*4882a593Smuzhiyun 	short p;
662*4882a593Smuzhiyun 	int status;
663*4882a593Smuzhiyun 	unsigned char Command0[6] = {0x80, 0x31, 0x00, 0x00, 0x00, 0x00};
664*4882a593Smuzhiyun 	unsigned char Command1[6] = {0x80, 0x32, 0x00, 0x00, 0x00, 0x00};
665*4882a593Smuzhiyun 	unsigned char Command2[6] = {0x80, 0x33, 0x00, 0x00, 0x00, 0x00};
666*4882a593Smuzhiyun 	unsigned char Command3[6] = {0x80, 0x34, 0x00, 0x00, 0x00, 0x00};
667*4882a593Smuzhiyun 
668*4882a593Smuzhiyun 	udelay(1000);
669*4882a593Smuzhiyun 	if ((status = sb1000_start_get_set_command(ioaddr, name)))
670*4882a593Smuzhiyun 		return status;
671*4882a593Smuzhiyun 
672*4882a593Smuzhiyun 	p = PID[0];
673*4882a593Smuzhiyun 	Command0[3] = p & 0xff;
674*4882a593Smuzhiyun 	p >>= 8;
675*4882a593Smuzhiyun 	Command0[2] = p & 0xff;
676*4882a593Smuzhiyun 	if ((status = card_send_command(ioaddr, name, Command0, st)))
677*4882a593Smuzhiyun 		return status;
678*4882a593Smuzhiyun 
679*4882a593Smuzhiyun 	p = PID[1];
680*4882a593Smuzhiyun 	Command1[3] = p & 0xff;
681*4882a593Smuzhiyun 	p >>= 8;
682*4882a593Smuzhiyun 	Command1[2] = p & 0xff;
683*4882a593Smuzhiyun 	if ((status = card_send_command(ioaddr, name, Command1, st)))
684*4882a593Smuzhiyun 		return status;
685*4882a593Smuzhiyun 
686*4882a593Smuzhiyun 	p = PID[2];
687*4882a593Smuzhiyun 	Command2[3] = p & 0xff;
688*4882a593Smuzhiyun 	p >>= 8;
689*4882a593Smuzhiyun 	Command2[2] = p & 0xff;
690*4882a593Smuzhiyun 	if ((status = card_send_command(ioaddr, name, Command2, st)))
691*4882a593Smuzhiyun 		return status;
692*4882a593Smuzhiyun 
693*4882a593Smuzhiyun 	p = PID[3];
694*4882a593Smuzhiyun 	Command3[3] = p & 0xff;
695*4882a593Smuzhiyun 	p >>= 8;
696*4882a593Smuzhiyun 	Command3[2] = p & 0xff;
697*4882a593Smuzhiyun 	if ((status = card_send_command(ioaddr, name, Command3, st)))
698*4882a593Smuzhiyun 		return status;
699*4882a593Smuzhiyun 
700*4882a593Smuzhiyun 	if ((status = card_send_command(ioaddr, name, Command4, st)))
701*4882a593Smuzhiyun 		return status;
702*4882a593Smuzhiyun 	return sb1000_end_get_set_command(ioaddr, name);
703*4882a593Smuzhiyun }
704*4882a593Smuzhiyun 
705*4882a593Smuzhiyun 
706*4882a593Smuzhiyun static void
sb1000_print_status_buffer(const char * name,unsigned char st[],unsigned char buffer[],int size)707*4882a593Smuzhiyun sb1000_print_status_buffer(const char* name, unsigned char st[],
708*4882a593Smuzhiyun 	unsigned char buffer[], int size)
709*4882a593Smuzhiyun {
710*4882a593Smuzhiyun 	int i, j, k;
711*4882a593Smuzhiyun 
712*4882a593Smuzhiyun 	printk(KERN_DEBUG "%s: status: %02x %02x\n", name, st[0], st[1]);
713*4882a593Smuzhiyun 	if (buffer[24] == 0x08 && buffer[25] == 0x00 && buffer[26] == 0x45) {
714*4882a593Smuzhiyun 		printk(KERN_DEBUG "%s: length: %d protocol: %d from: %d.%d.%d.%d:%d "
715*4882a593Smuzhiyun 			"to %d.%d.%d.%d:%d\n", name, buffer[28] << 8 | buffer[29],
716*4882a593Smuzhiyun 			buffer[35], buffer[38], buffer[39], buffer[40], buffer[41],
717*4882a593Smuzhiyun             buffer[46] << 8 | buffer[47],
718*4882a593Smuzhiyun 			buffer[42], buffer[43], buffer[44], buffer[45],
719*4882a593Smuzhiyun             buffer[48] << 8 | buffer[49]);
720*4882a593Smuzhiyun 	} else {
721*4882a593Smuzhiyun 		for (i = 0, k = 0; i < (size + 7) / 8; i++) {
722*4882a593Smuzhiyun 			printk(KERN_DEBUG "%s: %s", name, i ? "       " : "buffer:");
723*4882a593Smuzhiyun 			for (j = 0; j < 8 && k < size; j++, k++)
724*4882a593Smuzhiyun 				printk(" %02x", buffer[k]);
725*4882a593Smuzhiyun 			printk("\n");
726*4882a593Smuzhiyun 		}
727*4882a593Smuzhiyun 	}
728*4882a593Smuzhiyun }
729*4882a593Smuzhiyun 
730*4882a593Smuzhiyun /*
731*4882a593Smuzhiyun  * SB1000 commands for frame rx interrupt
732*4882a593Smuzhiyun  */
733*4882a593Smuzhiyun /* receive a single frame and assemble datagram
734*4882a593Smuzhiyun  * (this is the heart of the interrupt routine)
735*4882a593Smuzhiyun  */
736*4882a593Smuzhiyun static int
sb1000_rx(struct net_device * dev)737*4882a593Smuzhiyun sb1000_rx(struct net_device *dev)
738*4882a593Smuzhiyun {
739*4882a593Smuzhiyun 
740*4882a593Smuzhiyun #define FRAMESIZE 184
741*4882a593Smuzhiyun 	unsigned char st[2], buffer[FRAMESIZE], session_id, frame_id;
742*4882a593Smuzhiyun 	short dlen;
743*4882a593Smuzhiyun 	int ioaddr, ns;
744*4882a593Smuzhiyun 	unsigned int skbsize;
745*4882a593Smuzhiyun 	struct sk_buff *skb;
746*4882a593Smuzhiyun 	struct sb1000_private *lp = netdev_priv(dev);
747*4882a593Smuzhiyun 	struct net_device_stats *stats = &dev->stats;
748*4882a593Smuzhiyun 
749*4882a593Smuzhiyun 	/* SB1000 frame constants */
750*4882a593Smuzhiyun 	const int FrameSize = FRAMESIZE;
751*4882a593Smuzhiyun 	const int NewDatagramHeaderSkip = 8;
752*4882a593Smuzhiyun 	const int NewDatagramHeaderSize = NewDatagramHeaderSkip + 18;
753*4882a593Smuzhiyun 	const int NewDatagramDataSize = FrameSize - NewDatagramHeaderSize;
754*4882a593Smuzhiyun 	const int ContDatagramHeaderSkip = 7;
755*4882a593Smuzhiyun 	const int ContDatagramHeaderSize = ContDatagramHeaderSkip + 1;
756*4882a593Smuzhiyun 	const int ContDatagramDataSize = FrameSize - ContDatagramHeaderSize;
757*4882a593Smuzhiyun 	const int TrailerSize = 4;
758*4882a593Smuzhiyun 
759*4882a593Smuzhiyun 	ioaddr = dev->base_addr;
760*4882a593Smuzhiyun 
761*4882a593Smuzhiyun 	insw(ioaddr, (unsigned short*) st, 1);
762*4882a593Smuzhiyun #ifdef XXXDEBUG
763*4882a593Smuzhiyun printk("cm0: received: %02x %02x\n", st[0], st[1]);
764*4882a593Smuzhiyun #endif /* XXXDEBUG */
765*4882a593Smuzhiyun 	lp->rx_frames++;
766*4882a593Smuzhiyun 
767*4882a593Smuzhiyun 	/* decide if it is a good or bad frame */
768*4882a593Smuzhiyun 	for (ns = 0; ns < NPIDS; ns++) {
769*4882a593Smuzhiyun 		session_id = lp->rx_session_id[ns];
770*4882a593Smuzhiyun 		frame_id = lp->rx_frame_id[ns];
771*4882a593Smuzhiyun 		if (st[0] == session_id) {
772*4882a593Smuzhiyun 			if (st[1] == frame_id || (!frame_id && (st[1] & 0xf0) == 0x30)) {
773*4882a593Smuzhiyun 				goto good_frame;
774*4882a593Smuzhiyun 			} else if ((st[1] & 0xf0) == 0x30 && (st[0] & 0x40)) {
775*4882a593Smuzhiyun 				goto skipped_frame;
776*4882a593Smuzhiyun 			} else {
777*4882a593Smuzhiyun 				goto bad_frame;
778*4882a593Smuzhiyun 			}
779*4882a593Smuzhiyun 		} else if (st[0] == (session_id | 0x40)) {
780*4882a593Smuzhiyun 			if ((st[1] & 0xf0) == 0x30) {
781*4882a593Smuzhiyun 				goto skipped_frame;
782*4882a593Smuzhiyun 			} else {
783*4882a593Smuzhiyun 				goto bad_frame;
784*4882a593Smuzhiyun 			}
785*4882a593Smuzhiyun 		}
786*4882a593Smuzhiyun 	}
787*4882a593Smuzhiyun 	goto bad_frame;
788*4882a593Smuzhiyun 
789*4882a593Smuzhiyun skipped_frame:
790*4882a593Smuzhiyun 	stats->rx_frame_errors++;
791*4882a593Smuzhiyun 	skb = lp->rx_skb[ns];
792*4882a593Smuzhiyun 	if (sb1000_debug > 1)
793*4882a593Smuzhiyun 		printk(KERN_WARNING "%s: missing frame(s): got %02x %02x "
794*4882a593Smuzhiyun 			"expecting %02x %02x\n", dev->name, st[0], st[1],
795*4882a593Smuzhiyun 			skb ? session_id : session_id | 0x40, frame_id);
796*4882a593Smuzhiyun 	if (skb) {
797*4882a593Smuzhiyun 		dev_kfree_skb(skb);
798*4882a593Smuzhiyun 		skb = NULL;
799*4882a593Smuzhiyun 	}
800*4882a593Smuzhiyun 
801*4882a593Smuzhiyun good_frame:
802*4882a593Smuzhiyun 	lp->rx_frame_id[ns] = 0x30 | ((st[1] + 1) & 0x0f);
803*4882a593Smuzhiyun 	/* new datagram */
804*4882a593Smuzhiyun 	if (st[0] & 0x40) {
805*4882a593Smuzhiyun 		/* get data length */
806*4882a593Smuzhiyun 		insw(ioaddr, buffer, NewDatagramHeaderSize / 2);
807*4882a593Smuzhiyun #ifdef XXXDEBUG
808*4882a593Smuzhiyun printk("cm0: IP identification: %02x%02x  fragment offset: %02x%02x\n", buffer[30], buffer[31], buffer[32], buffer[33]);
809*4882a593Smuzhiyun #endif /* XXXDEBUG */
810*4882a593Smuzhiyun 		if (buffer[0] != NewDatagramHeaderSkip) {
811*4882a593Smuzhiyun 			if (sb1000_debug > 1)
812*4882a593Smuzhiyun 				printk(KERN_WARNING "%s: new datagram header skip error: "
813*4882a593Smuzhiyun 					"got %02x expecting %02x\n", dev->name, buffer[0],
814*4882a593Smuzhiyun 					NewDatagramHeaderSkip);
815*4882a593Smuzhiyun 			stats->rx_length_errors++;
816*4882a593Smuzhiyun 			insw(ioaddr, buffer, NewDatagramDataSize / 2);
817*4882a593Smuzhiyun 			goto bad_frame_next;
818*4882a593Smuzhiyun 		}
819*4882a593Smuzhiyun 		dlen = ((buffer[NewDatagramHeaderSkip + 3] & 0x0f) << 8 |
820*4882a593Smuzhiyun 			buffer[NewDatagramHeaderSkip + 4]) - 17;
821*4882a593Smuzhiyun 		if (dlen > SB1000_MRU) {
822*4882a593Smuzhiyun 			if (sb1000_debug > 1)
823*4882a593Smuzhiyun 				printk(KERN_WARNING "%s: datagram length (%d) greater "
824*4882a593Smuzhiyun 					"than MRU (%d)\n", dev->name, dlen, SB1000_MRU);
825*4882a593Smuzhiyun 			stats->rx_length_errors++;
826*4882a593Smuzhiyun 			insw(ioaddr, buffer, NewDatagramDataSize / 2);
827*4882a593Smuzhiyun 			goto bad_frame_next;
828*4882a593Smuzhiyun 		}
829*4882a593Smuzhiyun 		lp->rx_dlen[ns] = dlen;
830*4882a593Smuzhiyun 		/* compute size to allocate for datagram */
831*4882a593Smuzhiyun 		skbsize = dlen + FrameSize;
832*4882a593Smuzhiyun 		if ((skb = alloc_skb(skbsize, GFP_ATOMIC)) == NULL) {
833*4882a593Smuzhiyun 			if (sb1000_debug > 1)
834*4882a593Smuzhiyun 				printk(KERN_WARNING "%s: can't allocate %d bytes long "
835*4882a593Smuzhiyun 					"skbuff\n", dev->name, skbsize);
836*4882a593Smuzhiyun 			stats->rx_dropped++;
837*4882a593Smuzhiyun 			insw(ioaddr, buffer, NewDatagramDataSize / 2);
838*4882a593Smuzhiyun 			goto dropped_frame;
839*4882a593Smuzhiyun 		}
840*4882a593Smuzhiyun 		skb->dev = dev;
841*4882a593Smuzhiyun 		skb_reset_mac_header(skb);
842*4882a593Smuzhiyun 		skb->protocol = (unsigned short) buffer[NewDatagramHeaderSkip + 16];
843*4882a593Smuzhiyun 		insw(ioaddr, skb_put(skb, NewDatagramDataSize),
844*4882a593Smuzhiyun 			NewDatagramDataSize / 2);
845*4882a593Smuzhiyun 		lp->rx_skb[ns] = skb;
846*4882a593Smuzhiyun 	} else {
847*4882a593Smuzhiyun 		/* continuation of previous datagram */
848*4882a593Smuzhiyun 		insw(ioaddr, buffer, ContDatagramHeaderSize / 2);
849*4882a593Smuzhiyun 		if (buffer[0] != ContDatagramHeaderSkip) {
850*4882a593Smuzhiyun 			if (sb1000_debug > 1)
851*4882a593Smuzhiyun 				printk(KERN_WARNING "%s: cont datagram header skip error: "
852*4882a593Smuzhiyun 					"got %02x expecting %02x\n", dev->name, buffer[0],
853*4882a593Smuzhiyun 					ContDatagramHeaderSkip);
854*4882a593Smuzhiyun 			stats->rx_length_errors++;
855*4882a593Smuzhiyun 			insw(ioaddr, buffer, ContDatagramDataSize / 2);
856*4882a593Smuzhiyun 			goto bad_frame_next;
857*4882a593Smuzhiyun 		}
858*4882a593Smuzhiyun 		skb = lp->rx_skb[ns];
859*4882a593Smuzhiyun 		insw(ioaddr, skb_put(skb, ContDatagramDataSize),
860*4882a593Smuzhiyun 			ContDatagramDataSize / 2);
861*4882a593Smuzhiyun 		dlen = lp->rx_dlen[ns];
862*4882a593Smuzhiyun 	}
863*4882a593Smuzhiyun 	if (skb->len < dlen + TrailerSize) {
864*4882a593Smuzhiyun 		lp->rx_session_id[ns] &= ~0x40;
865*4882a593Smuzhiyun 		return 0;
866*4882a593Smuzhiyun 	}
867*4882a593Smuzhiyun 
868*4882a593Smuzhiyun 	/* datagram completed: send to upper level */
869*4882a593Smuzhiyun 	skb_trim(skb, dlen);
870*4882a593Smuzhiyun 	netif_rx(skb);
871*4882a593Smuzhiyun 	stats->rx_bytes+=dlen;
872*4882a593Smuzhiyun 	stats->rx_packets++;
873*4882a593Smuzhiyun 	lp->rx_skb[ns] = NULL;
874*4882a593Smuzhiyun 	lp->rx_session_id[ns] |= 0x40;
875*4882a593Smuzhiyun 	return 0;
876*4882a593Smuzhiyun 
877*4882a593Smuzhiyun bad_frame:
878*4882a593Smuzhiyun 	insw(ioaddr, buffer, FrameSize / 2);
879*4882a593Smuzhiyun 	if (sb1000_debug > 1)
880*4882a593Smuzhiyun 		printk(KERN_WARNING "%s: frame error: got %02x %02x\n",
881*4882a593Smuzhiyun 			dev->name, st[0], st[1]);
882*4882a593Smuzhiyun 	stats->rx_frame_errors++;
883*4882a593Smuzhiyun bad_frame_next:
884*4882a593Smuzhiyun 	if (sb1000_debug > 2)
885*4882a593Smuzhiyun 		sb1000_print_status_buffer(dev->name, st, buffer, FrameSize);
886*4882a593Smuzhiyun dropped_frame:
887*4882a593Smuzhiyun 	stats->rx_errors++;
888*4882a593Smuzhiyun 	if (ns < NPIDS) {
889*4882a593Smuzhiyun 		if ((skb = lp->rx_skb[ns])) {
890*4882a593Smuzhiyun 			dev_kfree_skb(skb);
891*4882a593Smuzhiyun 			lp->rx_skb[ns] = NULL;
892*4882a593Smuzhiyun 		}
893*4882a593Smuzhiyun 		lp->rx_session_id[ns] |= 0x40;
894*4882a593Smuzhiyun 	}
895*4882a593Smuzhiyun 	return -1;
896*4882a593Smuzhiyun }
897*4882a593Smuzhiyun 
898*4882a593Smuzhiyun static void
sb1000_error_dpc(struct net_device * dev)899*4882a593Smuzhiyun sb1000_error_dpc(struct net_device *dev)
900*4882a593Smuzhiyun {
901*4882a593Smuzhiyun 	static const unsigned char Command0[6] = {0x80, 0x26, 0x00, 0x00, 0x00, 0x00};
902*4882a593Smuzhiyun 
903*4882a593Smuzhiyun 	char *name;
904*4882a593Smuzhiyun 	unsigned char st[5];
905*4882a593Smuzhiyun 	int ioaddr[2];
906*4882a593Smuzhiyun 	struct sb1000_private *lp = netdev_priv(dev);
907*4882a593Smuzhiyun 	const int ErrorDpcCounterInitialize = 200;
908*4882a593Smuzhiyun 
909*4882a593Smuzhiyun 	ioaddr[0] = dev->base_addr;
910*4882a593Smuzhiyun 	/* mem_start holds the second I/O address */
911*4882a593Smuzhiyun 	ioaddr[1] = dev->mem_start;
912*4882a593Smuzhiyun 	name = dev->name;
913*4882a593Smuzhiyun 
914*4882a593Smuzhiyun 	sb1000_wait_for_ready_clear(ioaddr, name);
915*4882a593Smuzhiyun 	sb1000_send_command(ioaddr, name, Command0);
916*4882a593Smuzhiyun 	sb1000_wait_for_ready(ioaddr, name);
917*4882a593Smuzhiyun 	sb1000_read_status(ioaddr, st);
918*4882a593Smuzhiyun 	if (st[1] & 0x10)
919*4882a593Smuzhiyun 		lp->rx_error_dpc_count = ErrorDpcCounterInitialize;
920*4882a593Smuzhiyun }
921*4882a593Smuzhiyun 
922*4882a593Smuzhiyun 
923*4882a593Smuzhiyun /*
924*4882a593Smuzhiyun  * Linux interface functions
925*4882a593Smuzhiyun  */
926*4882a593Smuzhiyun static int
sb1000_open(struct net_device * dev)927*4882a593Smuzhiyun sb1000_open(struct net_device *dev)
928*4882a593Smuzhiyun {
929*4882a593Smuzhiyun 	char *name;
930*4882a593Smuzhiyun 	int ioaddr[2], status;
931*4882a593Smuzhiyun 	struct sb1000_private *lp = netdev_priv(dev);
932*4882a593Smuzhiyun 	const unsigned short FirmwareVersion[] = {0x01, 0x01};
933*4882a593Smuzhiyun 
934*4882a593Smuzhiyun 	ioaddr[0] = dev->base_addr;
935*4882a593Smuzhiyun 	/* mem_start holds the second I/O address */
936*4882a593Smuzhiyun 	ioaddr[1] = dev->mem_start;
937*4882a593Smuzhiyun 	name = dev->name;
938*4882a593Smuzhiyun 
939*4882a593Smuzhiyun 	/* initialize sb1000 */
940*4882a593Smuzhiyun 	if ((status = sb1000_reset(ioaddr, name)))
941*4882a593Smuzhiyun 		return status;
942*4882a593Smuzhiyun 	ssleep(1);
943*4882a593Smuzhiyun 	if ((status = sb1000_check_CRC(ioaddr, name)))
944*4882a593Smuzhiyun 		return status;
945*4882a593Smuzhiyun 
946*4882a593Smuzhiyun 	/* initialize private data before board can catch interrupts */
947*4882a593Smuzhiyun 	lp->rx_skb[0] = NULL;
948*4882a593Smuzhiyun 	lp->rx_skb[1] = NULL;
949*4882a593Smuzhiyun 	lp->rx_skb[2] = NULL;
950*4882a593Smuzhiyun 	lp->rx_skb[3] = NULL;
951*4882a593Smuzhiyun 	lp->rx_dlen[0] = 0;
952*4882a593Smuzhiyun 	lp->rx_dlen[1] = 0;
953*4882a593Smuzhiyun 	lp->rx_dlen[2] = 0;
954*4882a593Smuzhiyun 	lp->rx_dlen[3] = 0;
955*4882a593Smuzhiyun 	lp->rx_frames = 0;
956*4882a593Smuzhiyun 	lp->rx_error_count = 0;
957*4882a593Smuzhiyun 	lp->rx_error_dpc_count = 0;
958*4882a593Smuzhiyun 	lp->rx_session_id[0] = 0x50;
959*4882a593Smuzhiyun 	lp->rx_session_id[1] = 0x48;
960*4882a593Smuzhiyun 	lp->rx_session_id[2] = 0x44;
961*4882a593Smuzhiyun 	lp->rx_session_id[3] = 0x42;
962*4882a593Smuzhiyun 	lp->rx_frame_id[0] = 0;
963*4882a593Smuzhiyun 	lp->rx_frame_id[1] = 0;
964*4882a593Smuzhiyun 	lp->rx_frame_id[2] = 0;
965*4882a593Smuzhiyun 	lp->rx_frame_id[3] = 0;
966*4882a593Smuzhiyun 	if (request_irq(dev->irq, sb1000_interrupt, 0, "sb1000", dev)) {
967*4882a593Smuzhiyun 		return -EAGAIN;
968*4882a593Smuzhiyun 	}
969*4882a593Smuzhiyun 
970*4882a593Smuzhiyun 	if (sb1000_debug > 2)
971*4882a593Smuzhiyun 		printk(KERN_DEBUG "%s: Opening, IRQ %d\n", name, dev->irq);
972*4882a593Smuzhiyun 
973*4882a593Smuzhiyun 	/* Activate board and check firmware version */
974*4882a593Smuzhiyun 	udelay(1000);
975*4882a593Smuzhiyun 	if ((status = sb1000_activate(ioaddr, name)))
976*4882a593Smuzhiyun 		return status;
977*4882a593Smuzhiyun 	udelay(0);
978*4882a593Smuzhiyun 	if ((status = sb1000_get_firmware_version(ioaddr, name, version, 0)))
979*4882a593Smuzhiyun 		return status;
980*4882a593Smuzhiyun 	if (version[0] != FirmwareVersion[0] || version[1] != FirmwareVersion[1])
981*4882a593Smuzhiyun 		printk(KERN_WARNING "%s: found firmware version %x.%02x "
982*4882a593Smuzhiyun 			"(should be %x.%02x)\n", name, version[0], version[1],
983*4882a593Smuzhiyun 			FirmwareVersion[0], FirmwareVersion[1]);
984*4882a593Smuzhiyun 
985*4882a593Smuzhiyun 
986*4882a593Smuzhiyun 	netif_start_queue(dev);
987*4882a593Smuzhiyun 	return 0;					/* Always succeed */
988*4882a593Smuzhiyun }
989*4882a593Smuzhiyun 
sb1000_dev_ioctl(struct net_device * dev,struct ifreq * ifr,int cmd)990*4882a593Smuzhiyun static int sb1000_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
991*4882a593Smuzhiyun {
992*4882a593Smuzhiyun 	char* name;
993*4882a593Smuzhiyun 	unsigned char version[2];
994*4882a593Smuzhiyun 	short PID[4];
995*4882a593Smuzhiyun 	int ioaddr[2], status, frequency;
996*4882a593Smuzhiyun 	unsigned int stats[5];
997*4882a593Smuzhiyun 	struct sb1000_private *lp = netdev_priv(dev);
998*4882a593Smuzhiyun 
999*4882a593Smuzhiyun 	if (!(dev && dev->flags & IFF_UP))
1000*4882a593Smuzhiyun 		return -ENODEV;
1001*4882a593Smuzhiyun 
1002*4882a593Smuzhiyun 	ioaddr[0] = dev->base_addr;
1003*4882a593Smuzhiyun 	/* mem_start holds the second I/O address */
1004*4882a593Smuzhiyun 	ioaddr[1] = dev->mem_start;
1005*4882a593Smuzhiyun 	name = dev->name;
1006*4882a593Smuzhiyun 
1007*4882a593Smuzhiyun 	switch (cmd) {
1008*4882a593Smuzhiyun 	case SIOCGCMSTATS:		/* get statistics */
1009*4882a593Smuzhiyun 		stats[0] = dev->stats.rx_bytes;
1010*4882a593Smuzhiyun 		stats[1] = lp->rx_frames;
1011*4882a593Smuzhiyun 		stats[2] = dev->stats.rx_packets;
1012*4882a593Smuzhiyun 		stats[3] = dev->stats.rx_errors;
1013*4882a593Smuzhiyun 		stats[4] = dev->stats.rx_dropped;
1014*4882a593Smuzhiyun 		if(copy_to_user(ifr->ifr_data, stats, sizeof(stats)))
1015*4882a593Smuzhiyun 			return -EFAULT;
1016*4882a593Smuzhiyun 		status = 0;
1017*4882a593Smuzhiyun 		break;
1018*4882a593Smuzhiyun 
1019*4882a593Smuzhiyun 	case SIOCGCMFIRMWARE:		/* get firmware version */
1020*4882a593Smuzhiyun 		if ((status = sb1000_get_firmware_version(ioaddr, name, version, 1)))
1021*4882a593Smuzhiyun 			return status;
1022*4882a593Smuzhiyun 		if(copy_to_user(ifr->ifr_data, version, sizeof(version)))
1023*4882a593Smuzhiyun 			return -EFAULT;
1024*4882a593Smuzhiyun 		break;
1025*4882a593Smuzhiyun 
1026*4882a593Smuzhiyun 	case SIOCGCMFREQUENCY:		/* get frequency */
1027*4882a593Smuzhiyun 		if ((status = sb1000_get_frequency(ioaddr, name, &frequency)))
1028*4882a593Smuzhiyun 			return status;
1029*4882a593Smuzhiyun 		if(put_user(frequency, (int __user *) ifr->ifr_data))
1030*4882a593Smuzhiyun 			return -EFAULT;
1031*4882a593Smuzhiyun 		break;
1032*4882a593Smuzhiyun 
1033*4882a593Smuzhiyun 	case SIOCSCMFREQUENCY:		/* set frequency */
1034*4882a593Smuzhiyun 		if (!capable(CAP_NET_ADMIN))
1035*4882a593Smuzhiyun 			return -EPERM;
1036*4882a593Smuzhiyun 		if(get_user(frequency, (int __user *) ifr->ifr_data))
1037*4882a593Smuzhiyun 			return -EFAULT;
1038*4882a593Smuzhiyun 		if ((status = sb1000_set_frequency(ioaddr, name, frequency)))
1039*4882a593Smuzhiyun 			return status;
1040*4882a593Smuzhiyun 		break;
1041*4882a593Smuzhiyun 
1042*4882a593Smuzhiyun 	case SIOCGCMPIDS:			/* get PIDs */
1043*4882a593Smuzhiyun 		if ((status = sb1000_get_PIDs(ioaddr, name, PID)))
1044*4882a593Smuzhiyun 			return status;
1045*4882a593Smuzhiyun 		if(copy_to_user(ifr->ifr_data, PID, sizeof(PID)))
1046*4882a593Smuzhiyun 			return -EFAULT;
1047*4882a593Smuzhiyun 		break;
1048*4882a593Smuzhiyun 
1049*4882a593Smuzhiyun 	case SIOCSCMPIDS:			/* set PIDs */
1050*4882a593Smuzhiyun 		if (!capable(CAP_NET_ADMIN))
1051*4882a593Smuzhiyun 			return -EPERM;
1052*4882a593Smuzhiyun 		if(copy_from_user(PID, ifr->ifr_data, sizeof(PID)))
1053*4882a593Smuzhiyun 			return -EFAULT;
1054*4882a593Smuzhiyun 		if ((status = sb1000_set_PIDs(ioaddr, name, PID)))
1055*4882a593Smuzhiyun 			return status;
1056*4882a593Smuzhiyun 		/* set session_id, frame_id and pkt_type too */
1057*4882a593Smuzhiyun 		lp->rx_session_id[0] = 0x50 | (PID[0] & 0x0f);
1058*4882a593Smuzhiyun 		lp->rx_session_id[1] = 0x48;
1059*4882a593Smuzhiyun 		lp->rx_session_id[2] = 0x44;
1060*4882a593Smuzhiyun 		lp->rx_session_id[3] = 0x42;
1061*4882a593Smuzhiyun 		lp->rx_frame_id[0] = 0;
1062*4882a593Smuzhiyun 		lp->rx_frame_id[1] = 0;
1063*4882a593Smuzhiyun 		lp->rx_frame_id[2] = 0;
1064*4882a593Smuzhiyun 		lp->rx_frame_id[3] = 0;
1065*4882a593Smuzhiyun 		break;
1066*4882a593Smuzhiyun 
1067*4882a593Smuzhiyun 	default:
1068*4882a593Smuzhiyun 		status = -EINVAL;
1069*4882a593Smuzhiyun 		break;
1070*4882a593Smuzhiyun 	}
1071*4882a593Smuzhiyun 	return status;
1072*4882a593Smuzhiyun }
1073*4882a593Smuzhiyun 
1074*4882a593Smuzhiyun /* transmit function: do nothing since SB1000 can't send anything out */
1075*4882a593Smuzhiyun static netdev_tx_t
sb1000_start_xmit(struct sk_buff * skb,struct net_device * dev)1076*4882a593Smuzhiyun sb1000_start_xmit(struct sk_buff *skb, struct net_device *dev)
1077*4882a593Smuzhiyun {
1078*4882a593Smuzhiyun 	printk(KERN_WARNING "%s: trying to transmit!!!\n", dev->name);
1079*4882a593Smuzhiyun 	/* sb1000 can't xmit datagrams */
1080*4882a593Smuzhiyun 	dev_kfree_skb(skb);
1081*4882a593Smuzhiyun 	return NETDEV_TX_OK;
1082*4882a593Smuzhiyun }
1083*4882a593Smuzhiyun 
1084*4882a593Smuzhiyun /* SB1000 interrupt handler. */
sb1000_interrupt(int irq,void * dev_id)1085*4882a593Smuzhiyun static irqreturn_t sb1000_interrupt(int irq, void *dev_id)
1086*4882a593Smuzhiyun {
1087*4882a593Smuzhiyun 	static const unsigned char Command0[6] = {0x80, 0x2c, 0x00, 0x00, 0x00, 0x00};
1088*4882a593Smuzhiyun 	static const unsigned char Command1[6] = {0x80, 0x2e, 0x00, 0x00, 0x00, 0x00};
1089*4882a593Smuzhiyun 
1090*4882a593Smuzhiyun 	char *name;
1091*4882a593Smuzhiyun 	unsigned char st;
1092*4882a593Smuzhiyun 	int ioaddr[2];
1093*4882a593Smuzhiyun 	struct net_device *dev = dev_id;
1094*4882a593Smuzhiyun 	struct sb1000_private *lp = netdev_priv(dev);
1095*4882a593Smuzhiyun 
1096*4882a593Smuzhiyun 	const int MaxRxErrorCount = 6;
1097*4882a593Smuzhiyun 
1098*4882a593Smuzhiyun 	ioaddr[0] = dev->base_addr;
1099*4882a593Smuzhiyun 	/* mem_start holds the second I/O address */
1100*4882a593Smuzhiyun 	ioaddr[1] = dev->mem_start;
1101*4882a593Smuzhiyun 	name = dev->name;
1102*4882a593Smuzhiyun 
1103*4882a593Smuzhiyun 	/* is it a good interrupt? */
1104*4882a593Smuzhiyun 	st = inb(ioaddr[1] + 6);
1105*4882a593Smuzhiyun 	if (!(st & 0x08 && st & 0x20)) {
1106*4882a593Smuzhiyun 		return IRQ_NONE;
1107*4882a593Smuzhiyun 	}
1108*4882a593Smuzhiyun 
1109*4882a593Smuzhiyun 	if (sb1000_debug > 3)
1110*4882a593Smuzhiyun 		printk(KERN_DEBUG "%s: entering interrupt\n", dev->name);
1111*4882a593Smuzhiyun 
1112*4882a593Smuzhiyun 	st = inb(ioaddr[0] + 7);
1113*4882a593Smuzhiyun 	if (sb1000_rx(dev))
1114*4882a593Smuzhiyun 		lp->rx_error_count++;
1115*4882a593Smuzhiyun #ifdef SB1000_DELAY
1116*4882a593Smuzhiyun 	udelay(SB1000_DELAY);
1117*4882a593Smuzhiyun #endif /* SB1000_DELAY */
1118*4882a593Smuzhiyun 	sb1000_issue_read_command(ioaddr, name);
1119*4882a593Smuzhiyun 	if (st & 0x01) {
1120*4882a593Smuzhiyun 		sb1000_error_dpc(dev);
1121*4882a593Smuzhiyun 		sb1000_issue_read_command(ioaddr, name);
1122*4882a593Smuzhiyun 	}
1123*4882a593Smuzhiyun 	if (lp->rx_error_dpc_count && !(--lp->rx_error_dpc_count)) {
1124*4882a593Smuzhiyun 		sb1000_wait_for_ready_clear(ioaddr, name);
1125*4882a593Smuzhiyun 		sb1000_send_command(ioaddr, name, Command0);
1126*4882a593Smuzhiyun 		sb1000_wait_for_ready(ioaddr, name);
1127*4882a593Smuzhiyun 		sb1000_issue_read_command(ioaddr, name);
1128*4882a593Smuzhiyun 	}
1129*4882a593Smuzhiyun 	if (lp->rx_error_count >= MaxRxErrorCount) {
1130*4882a593Smuzhiyun 		sb1000_wait_for_ready_clear(ioaddr, name);
1131*4882a593Smuzhiyun 		sb1000_send_command(ioaddr, name, Command1);
1132*4882a593Smuzhiyun 		sb1000_wait_for_ready(ioaddr, name);
1133*4882a593Smuzhiyun 		sb1000_issue_read_command(ioaddr, name);
1134*4882a593Smuzhiyun 		lp->rx_error_count = 0;
1135*4882a593Smuzhiyun 	}
1136*4882a593Smuzhiyun 
1137*4882a593Smuzhiyun 	return IRQ_HANDLED;
1138*4882a593Smuzhiyun }
1139*4882a593Smuzhiyun 
sb1000_close(struct net_device * dev)1140*4882a593Smuzhiyun static int sb1000_close(struct net_device *dev)
1141*4882a593Smuzhiyun {
1142*4882a593Smuzhiyun 	int i;
1143*4882a593Smuzhiyun 	int ioaddr[2];
1144*4882a593Smuzhiyun 	struct sb1000_private *lp = netdev_priv(dev);
1145*4882a593Smuzhiyun 
1146*4882a593Smuzhiyun 	if (sb1000_debug > 2)
1147*4882a593Smuzhiyun 		printk(KERN_DEBUG "%s: Shutting down sb1000.\n", dev->name);
1148*4882a593Smuzhiyun 
1149*4882a593Smuzhiyun 	netif_stop_queue(dev);
1150*4882a593Smuzhiyun 
1151*4882a593Smuzhiyun 	ioaddr[0] = dev->base_addr;
1152*4882a593Smuzhiyun 	/* mem_start holds the second I/O address */
1153*4882a593Smuzhiyun 	ioaddr[1] = dev->mem_start;
1154*4882a593Smuzhiyun 
1155*4882a593Smuzhiyun 	free_irq(dev->irq, dev);
1156*4882a593Smuzhiyun 	/* If we don't do this, we can't re-insmod it later. */
1157*4882a593Smuzhiyun 	release_region(ioaddr[1], SB1000_IO_EXTENT);
1158*4882a593Smuzhiyun 	release_region(ioaddr[0], SB1000_IO_EXTENT);
1159*4882a593Smuzhiyun 
1160*4882a593Smuzhiyun 	/* free rx_skb's if needed */
1161*4882a593Smuzhiyun 	for (i=0; i<4; i++) {
1162*4882a593Smuzhiyun 		if (lp->rx_skb[i]) {
1163*4882a593Smuzhiyun 			dev_kfree_skb(lp->rx_skb[i]);
1164*4882a593Smuzhiyun 		}
1165*4882a593Smuzhiyun 	}
1166*4882a593Smuzhiyun 	return 0;
1167*4882a593Smuzhiyun }
1168*4882a593Smuzhiyun 
1169*4882a593Smuzhiyun MODULE_AUTHOR("Franco Venturi <fventuri@mediaone.net>");
1170*4882a593Smuzhiyun MODULE_DESCRIPTION("General Instruments SB1000 driver");
1171*4882a593Smuzhiyun MODULE_LICENSE("GPL");
1172*4882a593Smuzhiyun 
1173*4882a593Smuzhiyun module_pnp_driver(sb1000_driver);
1174