File: /usr/src/linux/drivers/net/wan/cycx_main.c

1     /*
2     * cycx_main.c	Cyclades Cyclom 2X WAN Link Driver. Main module.
3     *
4     * Author:	Arnaldo Carvalho de Melo <acme@conectiva.com.br>
5     *
6     * Copyright:	(c) 1998-2001 Arnaldo Carvalho de Melo
7     *
8     * Based on sdlamain.c by Gene Kozin <genek@compuserve.com> &
9     *			 Jaspreet Singh	<jaspreet@sangoma.com>
10     *
11     *		This program is free software; you can redistribute it and/or
12     *		modify it under the terms of the GNU General Public License
13     *		as published by the Free Software Foundation; either version
14     *		2 of the License, or (at your option) any later version.
15     * ============================================================================
16     * 2001/05/09	acme		Fix MODULE_DESC for debug, .bss nitpicks,
17     * 				some cleanups
18     * 2000/07/13	acme		remove useless #ifdef MODULE and crap
19     *				#if KERNEL_VERSION > blah
20     * 2000/07/06	acme		__exit at cyclomx_cleanup
21     * 2000/04/02	acme		dprintk and cycx_debug
22     * 				module_init/module_exit
23     * 2000/01/21	acme		rename cyclomx_open to cyclomx_mod_inc_use_count
24     *				and cyclomx_close to cyclomx_mod_dec_use_count
25     * 2000/01/08	acme		cleanup
26     * 1999/11/06	acme		cycx_down back to life (it needs to be
27     *				called to iounmap the dpmbase)
28     * 1999/08/09	acme		removed references to enable_tx_int
29     *				use spinlocks instead of cli/sti in
30     *				cyclomx_set_state
31     * 1999/05/19	acme		works directly linked into the kernel
32     *				init_waitqueue_head for 2.3.* kernel
33     * 1999/05/18	acme		major cleanup (polling not needed), etc
34     * 1998/08/28	acme		minor cleanup (ioctls for firmware deleted)
35     *				queue_task activated
36     * 1998/08/08	acme		Initial version.
37     */
38     
39     #include <linux/config.h>	/* OS configuration options */
40     #include <linux/stddef.h>	/* offsetof(), etc. */
41     #include <linux/errno.h>	/* return codes */
42     #include <linux/string.h>	/* inline memset(), etc. */
43     #include <linux/slab.h>		/* kmalloc(), kfree() */
44     #include <linux/kernel.h>	/* printk(), and other useful stuff */
45     #include <linux/module.h>	/* support for loadable modules */
46     #include <linux/ioport.h>	/* request_region(), release_region() */
47     #include <linux/tqueue.h>	/* for kernel task queues */
48     #include <linux/wanrouter.h>	/* WAN router definitions */
49     #include <linux/cyclomx.h>	/* cyclomx common user API definitions */
50     #include <asm/uaccess.h>	/* kernel <-> user copy */
51     #include <linux/init.h>         /* __init (when not using as a module) */
52     
53     /* Debug */
54     
55     unsigned int cycx_debug;
56     
57     MODULE_AUTHOR("Arnaldo Carvalho de Melo");
58     MODULE_DESCRIPTION("Cyclom 2X Sync Card Driver.");
59     MODULE_LICENSE("GPL");
60     MODULE_PARM(cycx_debug, "i");
61     MODULE_PARM_DESC(cycx_debug, "cyclomx debug level");
62     
63     /* Defines & Macros */
64     
65     #define	DRV_VERSION	0		/* version number */
66     #define	DRV_RELEASE	10		/* release (minor version) number */
67     #define	MAX_CARDS	1		/* max number of adapters */
68     
69     #define	CONFIG_CYCLOMX_CARDS 1
70     
71     /* Function Prototypes */
72     
73     /* WAN link driver entry points */
74     static int setup (wan_device_t *wandev, wandev_conf_t *conf);
75     static int shutdown (wan_device_t *wandev);
76     static int ioctl (wan_device_t *wandev, unsigned cmd, unsigned long arg);
77     
78     /* Miscellaneous functions */
79     static void cycx_isr (int irq, void *dev_id, struct pt_regs *regs);
80     
81     /* Global Data
82      * Note: All data must be explicitly initialized!!!
83      */
84     
85     /* private data */
86     static char drvname[]	= "cyclomx";
87     static char fullname[]	= "CYCLOM 2X(tm) Sync Card Driver";
88     static char copyright[] = "(c) 1998-2001 Arnaldo Carvalho de Melo "
89     			  "<acme@conectiva.com.br>";
90     static int ncards = CONFIG_CYCLOMX_CARDS;
91     static cycx_t *card_array;	/* adapter data space */
92     
93     /* Kernel Loadable Module Entry Points */
94     
95     /*
96      * Module 'insert' entry point.
97      * o print announcement
98      * o allocate adapter data space
99      * o initialize static data
100      * o register all cards with WAN router
101      * o calibrate Cyclom 2X shared memory access delay.
102      *
103      * Return:	0	Ok
104      *		< 0	error.
105      * Context:	process
106      */
107     int __init cyclomx_init (void)
108     {
109     	int cnt, err = -ENOMEM;
110     
111     	printk(KERN_INFO "%s v%u.%u %s\n",
112     		fullname, DRV_VERSION, DRV_RELEASE, copyright);
113     
114     	/* Verify number of cards and allocate adapter data space */
115     	ncards = min_t(int, ncards, MAX_CARDS);
116     	ncards = max_t(int, ncards, 1);
117     	card_array = kmalloc(sizeof(cycx_t) * ncards, GFP_KERNEL);
118     	if (!card_array)
119     		goto out;
120     
121     	memset(card_array, 0, sizeof(cycx_t) * ncards);
122     
123     	/* Register adapters with WAN router */
124     	for (cnt = 0; cnt < ncards; ++cnt) {
125     		cycx_t *card = &card_array[cnt];
126     		wan_device_t *wandev = &card->wandev;
127     
128     		sprintf(card->devname, "%s%d", drvname, cnt + 1);
129     		wandev->magic    = ROUTER_MAGIC;
130     		wandev->name     = card->devname;
131     		wandev->private  = card;
132     		wandev->setup    = setup;
133     		wandev->shutdown = shutdown;
134     		wandev->ioctl    = ioctl;
135     		err = register_wan_device(wandev);
136     
137     		if (err) {
138     			printk(KERN_ERR "%s: %s registration failed with "
139     					"error %d!\n",
140     					drvname, card->devname, err);
141     			break;
142     		}
143     	}
144     
145     	err = -ENODEV;
146     	if (!cnt) {
147     		kfree(card_array);
148     		goto out;
149     	}
150     	err = 0;
151     	ncards = cnt;	/* adjust actual number of cards */
152     out:	return err;
153     }
154     
155     /*
156      * Module 'remove' entry point.
157      * o unregister all adapters from the WAN router
158      * o release all remaining system resources
159      */
160     static void __exit cyclomx_cleanup (void)
161     {
162     	int i = 0;
163     
164     	for (; i < ncards; ++i) {
165     		cycx_t *card = &card_array[i];
166     		unregister_wan_device(card->devname);
167     	}
168     
169     	kfree(card_array);
170     }
171     
172     /* WAN Device Driver Entry Points */
173     /*
174      * Setup/configure WAN link driver.
175      * o check adapter state
176      * o make sure firmware is present in configuration
177      * o allocate interrupt vector
178      * o setup Cyclom 2X hardware
179      * o call appropriate routine to perform protocol-specific initialization
180      *
181      * This function is called when router handles ROUTER_SETUP IOCTL. The
182      * configuration structure is in kernel memory (including extended data, if
183      * any).
184      */
185     static int setup (wan_device_t *wandev, wandev_conf_t *conf)
186     {
187     	int err = -EFAULT;
188     	cycx_t *card;
189     	int irq;
190     
191     	/* Sanity checks */
192     	
193     	if (!wandev || !wandev->private || !conf)
194     		goto out;
195     
196     	card = wandev->private;
197     	err = -EBUSY;
198     	if (wandev->state != WAN_UNCONFIGURED)
199     		goto out;
200     
201     	err = -EINVAL;
202     	if (!conf->data_size || !conf->data) {
203     		printk(KERN_ERR "%s: firmware not found in configuration "
204     				"data!\n", wandev->name);
205     		goto out;
206     	}
207     
208     	if (conf->irq <= 0) {
209     		printk(KERN_ERR "%s: can't configure without IRQ!\n",
210     				wandev->name);
211     		goto out;
212     	}
213     
214     	/* Allocate IRQ */
215     	irq = conf->irq == 2 ? 9 : conf->irq;	/* IRQ2 -> IRQ9 */
216     
217     	if (request_irq(irq, cycx_isr, 0, wandev->name, card)) {
218     		printk(KERN_ERR "%s: can't reserve IRQ %d!\n",
219     				wandev->name, irq);
220     		goto out;
221     	}
222     
223     	/* Configure hardware, load firmware, etc. */
224     	memset(&card->hw, 0, sizeof(cycxhw_t));
225     	card->hw.irq	 = irq;
226     	card->hw.dpmbase = conf->maddr;
227     	card->hw.dpmsize = CYCX_WINDOWSIZE;
228     	card->hw.fwid	 = CFID_X25_2X;
229     	card->lock	 = SPIN_LOCK_UNLOCKED;
230     	init_waitqueue_head(&card->wait_stats);
231     
232     	err = cycx_setup(&card->hw, conf->data, conf->data_size);
233     	if (err)
234     		goto out_irq;
235     
236     	/* Initialize WAN device data space */
237     	wandev->irq       = irq;
238     	wandev->dma       = wandev->ioport = 0;
239     	wandev->maddr     = card->hw.dpmbase;
240     	wandev->msize     = card->hw.dpmsize;
241     	wandev->hw_opt[2] = 0;
242     	wandev->hw_opt[3] = card->hw.fwid;
243     
244     	/* Protocol-specific initialization */
245     	switch (card->hw.fwid) {
246     #ifdef CONFIG_CYCLOMX_X25
247     		case CFID_X25_2X:
248     			err = cyx_init(card, conf);
249     			break;
250     #endif
251     		default:
252     			printk(KERN_ERR "%s: this firmware is not supported!\n",
253     					wandev->name);
254     			err = -EINVAL;
255     	}
256     
257     	if (err) {
258     		cycx_down(&card->hw);
259     		goto out_irq;
260     	}
261     
262     	err = 0;
263     out:	return err;
264     out_irq:
265     	free_irq(irq, card);
266     	goto out;
267     }
268     
269     /*
270      * Shut down WAN link driver. 
271      * o shut down adapter hardware
272      * o release system resources.
273      *
274      * This function is called by the router when device is being unregistered or
275      * when it handles ROUTER_DOWN IOCTL.
276      */
277     static int shutdown (wan_device_t *wandev)
278     {
279     	int ret = -EFAULT;
280     	cycx_t *card;
281     
282     	/* sanity checks */
283     	if (!wandev || !wandev->private)
284     		goto out;
285     
286     	ret = 0;
287     	if (wandev->state == WAN_UNCONFIGURED)
288     		goto out;
289     
290     	card = wandev->private;
291     	wandev->state = WAN_UNCONFIGURED;
292     	cycx_down(&card->hw);
293     	printk(KERN_INFO "%s: irq %d being freed!\n", wandev->name,
294     			wandev->irq);
295     	free_irq(wandev->irq, card);
296     out:	return ret;
297     }
298     
299     /*
300      * Driver I/O control. 
301      * o verify arguments
302      * o perform requested action
303      *
304      * This function is called when router handles one of the reserved user
305      * IOCTLs.  Note that 'arg' still points to user address space.
306      *
307      * no reserved ioctls for the cyclom 2x up to now
308      */
309     static int ioctl (wan_device_t *wandev, unsigned cmd, unsigned long arg)
310     {
311     	return -EINVAL;
312     }
313     
314     /* Miscellaneous */
315     /*
316      * Cyclom 2X Interrupt Service Routine.
317      * o acknowledge Cyclom 2X hardware interrupt.
318      * o call protocol-specific interrupt service routine, if any.
319      */
320     static void cycx_isr (int irq, void *dev_id, struct pt_regs *regs)
321     {
322     	cycx_t *card = (cycx_t *)dev_id;
323     
324     	if (!card || card->wandev.state == WAN_UNCONFIGURED)
325     		goto out;
326     
327     	if (card->in_isr) {
328     		printk(KERN_WARNING "%s: interrupt re-entrancy on IRQ %d!\n",
329     				    card->devname, card->wandev.irq);
330     		goto out;
331     	}
332     
333     	if (card->isr)
334     		card->isr(card);
335     out:	return;
336     }
337     
338     /*
339      * This routine is called by the protocol-specific modules when network
340      * interface is being open.  The only reason we need this, is because we
341      * have to call MOD_INC_USE_COUNT, but cannot include 'module.h' where it's
342      * defined more than once into the same kernel module.
343      */
344     void cyclomx_mod_inc_use_count (cycx_t *card)
345     {
346     	++card->open_cnt;
347     	MOD_INC_USE_COUNT;
348     }
349     
350     /*
351      * This routine is called by the protocol-specific modules when network
352      * interface is being closed.  The only reason we need this, is because we
353      * have to call MOD_DEC_USE_COUNT, but cannot include 'module.h' where it's
354      * defined more than once into the same kernel module.
355      */
356     void cyclomx_mod_dec_use_count (cycx_t *card)
357     {
358     	--card->open_cnt;
359     	MOD_DEC_USE_COUNT;
360     }
361     
362     /* Set WAN device state.  */
363     void cyclomx_set_state (cycx_t *card, int state)
364     {
365     	unsigned long flags;
366     	char *string_state = NULL;
367     
368     	spin_lock_irqsave(&card->lock, flags);
369     
370     	if (card->wandev.state != state) {
371     		switch (state) {
372     			case WAN_CONNECTED:
373     				string_state = "connected!";
374     				break;
375     
376     			case WAN_DISCONNECTED:
377     				string_state = "disconnected!";
378     				break;
379     		}
380     
381     		printk(KERN_INFO "%s: link %s\n", card->devname, string_state);
382     		card->wandev.state = state;
383     	}
384     
385     	card->state_tick = jiffies;
386     	spin_unlock_irqrestore(&card->lock, flags);
387     }
388     
389     module_init(cyclomx_init);
390     module_exit(cyclomx_cleanup);
391