1/*
2 * Copyright 2003 Digi International (www.digi.com)
3 *	Scott H Kilau <Scott_Kilau at digi dot com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the
12 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
13 * PURPOSE.  See the GNU General Public License for more details.
14 */
15
16
17#include <linux/kernel.h>
18#include <linux/module.h>
19#include <linux/pci.h>
20#include <linux/slab.h>
21#include <linux/sched.h>
22#include "dgnc_driver.h"
23#include "dgnc_pci.h"
24#include "dgnc_mgmt.h"
25#include "dgnc_tty.h"
26#include "dgnc_cls.h"
27#include "dgnc_neo.h"
28#include "dgnc_sysfs.h"
29
30MODULE_LICENSE("GPL");
31MODULE_AUTHOR("Digi International, http://www.digi.com");
32MODULE_DESCRIPTION("Driver for the Digi International Neo and Classic PCI based product line");
33MODULE_SUPPORTED_DEVICE("dgnc");
34
35/**************************************************************************
36 *
37 * protos for this file
38 *
39 */
40static int		dgnc_start(void);
41static int		dgnc_finalize_board_init(struct dgnc_board *brd);
42static void		dgnc_init_globals(void);
43static int		dgnc_found_board(struct pci_dev *pdev, int id);
44static void		dgnc_cleanup_board(struct dgnc_board *brd);
45static void		dgnc_poll_handler(ulong dummy);
46static int		dgnc_init_one(struct pci_dev *pdev,
47				      const struct pci_device_id *ent);
48static void		dgnc_do_remap(struct dgnc_board *brd);
49
50/*
51 * File operations permitted on Control/Management major.
52 */
53static const struct file_operations dgnc_BoardFops = {
54	.owner		=	THIS_MODULE,
55	.unlocked_ioctl =	dgnc_mgmt_ioctl,
56	.open		=	dgnc_mgmt_open,
57	.release	=	dgnc_mgmt_close
58};
59
60
61/*
62 * Globals
63 */
64uint			dgnc_NumBoards;
65struct dgnc_board		*dgnc_Board[MAXBOARDS];
66DEFINE_SPINLOCK(dgnc_global_lock);
67uint			dgnc_Major;
68int			dgnc_poll_tick = 20;	/* Poll interval - 20 ms */
69
70/*
71 * Static vars.
72 */
73static struct class *dgnc_class;
74
75/*
76 * Poller stuff
77 */
78static DEFINE_SPINLOCK(dgnc_poll_lock); /* Poll scheduling lock */
79static ulong		dgnc_poll_time; /* Time of next poll */
80static uint		dgnc_poll_stop; /* Used to tell poller to stop */
81static struct timer_list dgnc_poll_timer;
82
83
84static const struct pci_device_id dgnc_pci_tbl[] = {
85	{PCI_DEVICE(DIGI_VID, PCI_DEVICE_CLASSIC_4_DID),     .driver_data = 0},
86	{PCI_DEVICE(DIGI_VID, PCI_DEVICE_CLASSIC_4_422_DID), .driver_data = 1},
87	{PCI_DEVICE(DIGI_VID, PCI_DEVICE_CLASSIC_8_DID),     .driver_data = 2},
88	{PCI_DEVICE(DIGI_VID, PCI_DEVICE_CLASSIC_8_422_DID), .driver_data = 3},
89	{0,}
90};
91MODULE_DEVICE_TABLE(pci, dgnc_pci_tbl);
92
93struct board_id {
94	unsigned char *name;
95	uint maxports;
96	unsigned int is_pci_express;
97};
98
99static struct board_id dgnc_Ids[] = {
100	{	PCI_DEVICE_CLASSIC_4_PCI_NAME,		4,	0	},
101	{	PCI_DEVICE_CLASSIC_4_422_PCI_NAME,	4,	0	},
102	{	PCI_DEVICE_CLASSIC_8_PCI_NAME,		8,	0	},
103	{	PCI_DEVICE_CLASSIC_8_422_PCI_NAME,	8,	0	},
104	{	PCI_DEVICE_NEO_4_PCI_NAME,		4,	0	},
105	{	PCI_DEVICE_NEO_8_PCI_NAME,		8,	0	},
106	{	PCI_DEVICE_NEO_2DB9_PCI_NAME,		2,	0	},
107	{	PCI_DEVICE_NEO_2DB9PRI_PCI_NAME,	2,	0	},
108	{	PCI_DEVICE_NEO_2RJ45_PCI_NAME,		2,	0	},
109	{	PCI_DEVICE_NEO_2RJ45PRI_PCI_NAME,	2,	0	},
110	{	PCI_DEVICE_NEO_1_422_PCI_NAME,		1,	0	},
111	{	PCI_DEVICE_NEO_1_422_485_PCI_NAME,	1,	0	},
112	{	PCI_DEVICE_NEO_2_422_485_PCI_NAME,	2,	0	},
113	{	PCI_DEVICE_NEO_EXPRESS_8_PCI_NAME,	8,	1	},
114	{	PCI_DEVICE_NEO_EXPRESS_4_PCI_NAME,	4,	1	},
115	{	PCI_DEVICE_NEO_EXPRESS_4RJ45_PCI_NAME,	4,	1	},
116	{	PCI_DEVICE_NEO_EXPRESS_8RJ45_PCI_NAME,	8,	1	},
117	{	NULL,					0,	0	}
118};
119
120static struct pci_driver dgnc_driver = {
121	.name		= "dgnc",
122	.probe		= dgnc_init_one,
123	.id_table       = dgnc_pci_tbl,
124};
125
126/************************************************************************
127 *
128 * Driver load/unload functions
129 *
130 ************************************************************************/
131
132/*
133 * dgnc_cleanup_module()
134 *
135 * Module unload.  This is where it all ends.
136 */
137static void dgnc_cleanup_module(void)
138{
139	int i;
140	unsigned long flags;
141
142	spin_lock_irqsave(&dgnc_poll_lock, flags);
143	dgnc_poll_stop = 1;
144	spin_unlock_irqrestore(&dgnc_poll_lock, flags);
145
146	/* Turn off poller right away. */
147	del_timer_sync(&dgnc_poll_timer);
148
149	dgnc_remove_driver_sysfiles(&dgnc_driver);
150
151	device_destroy(dgnc_class, MKDEV(dgnc_Major, 0));
152	class_destroy(dgnc_class);
153	unregister_chrdev(dgnc_Major, "dgnc");
154
155	for (i = 0; i < dgnc_NumBoards; ++i) {
156		dgnc_remove_ports_sysfiles(dgnc_Board[i]);
157		dgnc_tty_uninit(dgnc_Board[i]);
158		dgnc_cleanup_board(dgnc_Board[i]);
159	}
160
161	dgnc_tty_post_uninit();
162
163	if (dgnc_NumBoards)
164		pci_unregister_driver(&dgnc_driver);
165}
166
167/*
168 * init_module()
169 *
170 * Module load.  This is where it all starts.
171 */
172static int __init dgnc_init_module(void)
173{
174	int rc = 0;
175
176	/*
177	 * Initialize global stuff
178	 */
179	rc = dgnc_start();
180
181	if (rc < 0)
182		return rc;
183
184	/*
185	 * Find and configure all the cards
186	 */
187	rc = pci_register_driver(&dgnc_driver);
188
189	/*
190	 * If something went wrong in the scan, bail out of driver.
191	 */
192	if (rc < 0) {
193		/* Only unregister if it was actually registered. */
194		if (dgnc_NumBoards)
195			pci_unregister_driver(&dgnc_driver);
196		else
197			pr_warn("WARNING: dgnc driver load failed.  No Digi Neo or Classic boards found.\n");
198
199		dgnc_cleanup_module();
200	} else {
201		dgnc_create_driver_sysfiles(&dgnc_driver);
202	}
203
204	return rc;
205}
206
207module_init(dgnc_init_module);
208module_exit(dgnc_cleanup_module);
209
210/*
211 * Start of driver.
212 */
213static int dgnc_start(void)
214{
215	int rc = 0;
216	unsigned long flags;
217	struct device *dev;
218
219	/* make sure that the globals are init'd before we do anything else */
220	dgnc_init_globals();
221
222	/*
223	 * Register our base character device into the kernel.
224	 * This allows the download daemon to connect to the downld device
225	 * before any of the boards are init'ed.
226	 *
227	 * Register management/dpa devices
228	 */
229	rc = register_chrdev(0, "dgnc", &dgnc_BoardFops);
230	if (rc < 0) {
231		pr_err(DRVSTR ": Can't register dgnc driver device (%d)\n", rc);
232		return rc;
233	}
234	dgnc_Major = rc;
235
236	dgnc_class = class_create(THIS_MODULE, "dgnc_mgmt");
237	if (IS_ERR(dgnc_class)) {
238		rc = PTR_ERR(dgnc_class);
239		pr_err(DRVSTR ": Can't create dgnc_mgmt class (%d)\n", rc);
240		goto failed_class;
241	}
242
243	dev = device_create(dgnc_class, NULL,
244			MKDEV(dgnc_Major, 0),
245			NULL, "dgnc_mgmt");
246	if (IS_ERR(dev)) {
247		rc = PTR_ERR(dev);
248		pr_err(DRVSTR ": Can't create device (%d)\n", rc);
249		goto failed_device;
250	}
251
252	/*
253	 * Init any global tty stuff.
254	 */
255	rc = dgnc_tty_preinit();
256
257	if (rc < 0) {
258		pr_err(DRVSTR ": tty preinit - not enough memory (%d)\n", rc);
259		goto failed_tty;
260	}
261
262	/* Start the poller */
263	spin_lock_irqsave(&dgnc_poll_lock, flags);
264	setup_timer(&dgnc_poll_timer, dgnc_poll_handler, 0);
265	dgnc_poll_time = jiffies + dgnc_jiffies_from_ms(dgnc_poll_tick);
266	dgnc_poll_timer.expires = dgnc_poll_time;
267	spin_unlock_irqrestore(&dgnc_poll_lock, flags);
268
269	add_timer(&dgnc_poll_timer);
270
271	return 0;
272
273failed_tty:
274	device_destroy(dgnc_class, MKDEV(dgnc_Major, 0));
275failed_device:
276	class_destroy(dgnc_class);
277failed_class:
278	unregister_chrdev(dgnc_Major, "dgnc");
279	return rc;
280}
281
282/* returns count (>= 0), or negative on error */
283static int dgnc_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
284{
285	int rc;
286
287	/* wake up and enable device */
288	rc = pci_enable_device(pdev);
289
290	if (rc < 0) {
291		rc = -EIO;
292	} else {
293		rc = dgnc_found_board(pdev, ent->driver_data);
294		if (rc == 0)
295			dgnc_NumBoards++;
296	}
297	return rc;
298}
299
300/*
301 * dgnc_cleanup_board()
302 *
303 * Free all the memory associated with a board
304 */
305static void dgnc_cleanup_board(struct dgnc_board *brd)
306{
307	int i = 0;
308
309	if (!brd || brd->magic != DGNC_BOARD_MAGIC)
310		return;
311
312	switch (brd->device) {
313	case PCI_DEVICE_CLASSIC_4_DID:
314	case PCI_DEVICE_CLASSIC_8_DID:
315	case PCI_DEVICE_CLASSIC_4_422_DID:
316	case PCI_DEVICE_CLASSIC_8_422_DID:
317
318		/* Tell card not to interrupt anymore. */
319		outb(0, brd->iobase + 0x4c);
320		break;
321
322	default:
323		break;
324	}
325
326	if (brd->irq)
327		free_irq(brd->irq, brd);
328
329	tasklet_kill(&brd->helper_tasklet);
330
331	if (brd->re_map_membase) {
332		iounmap(brd->re_map_membase);
333		brd->re_map_membase = NULL;
334	}
335
336	if (brd->msgbuf_head) {
337		unsigned long flags;
338
339		spin_lock_irqsave(&dgnc_global_lock, flags);
340		brd->msgbuf = NULL;
341		dev_dbg(&brd->pdev->dev, "%s\n", brd->msgbuf_head);
342		kfree(brd->msgbuf_head);
343		brd->msgbuf_head = NULL;
344		spin_unlock_irqrestore(&dgnc_global_lock, flags);
345	}
346
347	/* Free all allocated channels structs */
348	for (i = 0; i < MAXPORTS ; i++) {
349		if (brd->channels[i]) {
350			kfree(brd->channels[i]->ch_rqueue);
351			kfree(brd->channels[i]->ch_equeue);
352			kfree(brd->channels[i]->ch_wqueue);
353			kfree(brd->channels[i]);
354			brd->channels[i] = NULL;
355		}
356	}
357
358	kfree(brd->flipbuf);
359
360	dgnc_Board[brd->boardnum] = NULL;
361
362	kfree(brd);
363}
364
365
366/*
367 * dgnc_found_board()
368 *
369 * A board has been found, init it.
370 */
371static int dgnc_found_board(struct pci_dev *pdev, int id)
372{
373	struct dgnc_board *brd;
374	unsigned int pci_irq;
375	int i = 0;
376	int rc = 0;
377	unsigned long flags;
378
379	/* get the board structure and prep it */
380	dgnc_Board[dgnc_NumBoards] = kzalloc(sizeof(*brd), GFP_KERNEL);
381	brd = dgnc_Board[dgnc_NumBoards];
382
383	if (!brd)
384		return -ENOMEM;
385
386	/* make a temporary message buffer for the boot messages */
387	brd->msgbuf_head = kcalloc(8192, sizeof(u8), GFP_KERNEL);
388	brd->msgbuf = brd->msgbuf_head;
389
390	if (!brd->msgbuf) {
391		kfree(brd);
392		return -ENOMEM;
393	}
394
395	/* store the info for the board we've found */
396	brd->magic = DGNC_BOARD_MAGIC;
397	brd->boardnum = dgnc_NumBoards;
398	brd->vendor = dgnc_pci_tbl[id].vendor;
399	brd->device = dgnc_pci_tbl[id].device;
400	brd->pdev = pdev;
401	brd->pci_bus = pdev->bus->number;
402	brd->pci_slot = PCI_SLOT(pdev->devfn);
403	brd->name = dgnc_Ids[id].name;
404	brd->maxports = dgnc_Ids[id].maxports;
405	if (dgnc_Ids[i].is_pci_express)
406		brd->bd_flags |= BD_IS_PCI_EXPRESS;
407	brd->dpastatus = BD_NOFEP;
408	init_waitqueue_head(&brd->state_wait);
409
410	spin_lock_init(&brd->bd_lock);
411	spin_lock_init(&brd->bd_intr_lock);
412
413	brd->state		= BOARD_FOUND;
414
415	for (i = 0; i < MAXPORTS; i++)
416		brd->channels[i] = NULL;
417
418	/* store which card & revision we have */
419	pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &brd->subvendor);
420	pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &brd->subdevice);
421	pci_read_config_byte(pdev, PCI_REVISION_ID, &brd->rev);
422
423	pci_irq = pdev->irq;
424	brd->irq = pci_irq;
425
426
427	switch (brd->device) {
428
429	case PCI_DEVICE_CLASSIC_4_DID:
430	case PCI_DEVICE_CLASSIC_8_DID:
431	case PCI_DEVICE_CLASSIC_4_422_DID:
432	case PCI_DEVICE_CLASSIC_8_422_DID:
433
434		brd->dpatype = T_CLASSIC | T_PCIBUS;
435
436		/*
437		 * For PCI ClassicBoards
438		 * PCI Local Address (i.e. "resource" number) space
439		 * 0	PLX Memory Mapped Config
440		 * 1	PLX I/O Mapped Config
441		 * 2	I/O Mapped UARTs and Status
442		 * 3	Memory Mapped VPD
443		 * 4	Memory Mapped UARTs and Status
444		 */
445
446
447		/* get the PCI Base Address Registers */
448		brd->membase = pci_resource_start(pdev, 4);
449
450		if (!brd->membase) {
451			dev_err(&brd->pdev->dev,
452				"Card has no PCI IO resources, failing.\n");
453			return -ENODEV;
454		}
455
456		brd->membase_end = pci_resource_end(pdev, 4);
457
458		if (brd->membase & 1)
459			brd->membase &= ~3;
460		else
461			brd->membase &= ~15;
462
463		brd->iobase	= pci_resource_start(pdev, 1);
464		brd->iobase_end = pci_resource_end(pdev, 1);
465		brd->iobase	= ((unsigned int) (brd->iobase)) & 0xFFFE;
466
467		/* Assign the board_ops struct */
468		brd->bd_ops = &dgnc_cls_ops;
469
470		brd->bd_uart_offset = 0x8;
471		brd->bd_dividend = 921600;
472
473		dgnc_do_remap(brd);
474
475		/* Get and store the board VPD, if it exists */
476		brd->bd_ops->vpd(brd);
477
478		/*
479		 * Enable Local Interrupt 1		  (0x1),
480		 * Local Interrupt 1 Polarity Active high (0x2),
481		 * Enable PCI interrupt			  (0x40)
482		 */
483		outb(0x43, brd->iobase + 0x4c);
484
485		break;
486
487
488	case PCI_DEVICE_NEO_4_DID:
489	case PCI_DEVICE_NEO_8_DID:
490	case PCI_DEVICE_NEO_2DB9_DID:
491	case PCI_DEVICE_NEO_2DB9PRI_DID:
492	case PCI_DEVICE_NEO_2RJ45_DID:
493	case PCI_DEVICE_NEO_2RJ45PRI_DID:
494	case PCI_DEVICE_NEO_1_422_DID:
495	case PCI_DEVICE_NEO_1_422_485_DID:
496	case PCI_DEVICE_NEO_2_422_485_DID:
497	case PCI_DEVICE_NEO_EXPRESS_8_DID:
498	case PCI_DEVICE_NEO_EXPRESS_4_DID:
499	case PCI_DEVICE_NEO_EXPRESS_4RJ45_DID:
500	case PCI_DEVICE_NEO_EXPRESS_8RJ45_DID:
501
502		/*
503		 * This chip is set up 100% when we get to it.
504		 * No need to enable global interrupts or anything.
505		 */
506		if (brd->bd_flags & BD_IS_PCI_EXPRESS)
507			brd->dpatype = T_NEO_EXPRESS | T_PCIBUS;
508		else
509			brd->dpatype = T_NEO | T_PCIBUS;
510
511		/* get the PCI Base Address Registers */
512		brd->membase     = pci_resource_start(pdev, 0);
513		brd->membase_end = pci_resource_end(pdev, 0);
514
515		if (brd->membase & 1)
516			brd->membase &= ~3;
517		else
518			brd->membase &= ~15;
519
520		/* Assign the board_ops struct */
521		brd->bd_ops = &dgnc_neo_ops;
522
523		brd->bd_uart_offset = 0x200;
524		brd->bd_dividend = 921600;
525
526		dgnc_do_remap(brd);
527
528		if (brd->re_map_membase) {
529
530			/* Read and store the dvid after remapping */
531			brd->dvid = readb(brd->re_map_membase + 0x8D);
532
533			/* Get and store the board VPD, if it exists */
534			brd->bd_ops->vpd(brd);
535		}
536		break;
537
538	default:
539		dev_err(&brd->pdev->dev,
540			"Didn't find any compatible Neo/Classic PCI boards.\n");
541		return -ENXIO;
542
543	}
544
545	/*
546	 * Do tty device initialization.
547	 */
548
549	rc = dgnc_tty_register(brd);
550	if (rc < 0) {
551		pr_err(DRVSTR ": Can't register tty devices (%d)\n", rc);
552		goto failed;
553	}
554
555	rc = dgnc_finalize_board_init(brd);
556	if (rc < 0) {
557		pr_err(DRVSTR ": Can't finalize board init (%d)\n", rc);
558		goto failed;
559	}
560
561	rc = dgnc_tty_init(brd);
562	if (rc < 0) {
563		pr_err(DRVSTR ": Can't init tty devices (%d)\n", rc);
564		goto failed;
565	}
566
567	brd->state = BOARD_READY;
568	brd->dpastatus = BD_RUNNING;
569
570	dgnc_create_ports_sysfiles(brd);
571
572	/* init our poll helper tasklet */
573	tasklet_init(&brd->helper_tasklet,
574		     brd->bd_ops->tasklet,
575		     (unsigned long) brd);
576
577	spin_lock_irqsave(&dgnc_global_lock, flags);
578	brd->msgbuf = NULL;
579	dev_dbg(&brd->pdev->dev, "%s\n", brd->msgbuf_head);
580	kfree(brd->msgbuf_head);
581	brd->msgbuf_head = NULL;
582	spin_unlock_irqrestore(&dgnc_global_lock, flags);
583
584	/*
585	 * allocate flip buffer for board.
586	 *
587	 * Okay to malloc with GFP_KERNEL, we are not at interrupt
588	 * context, and there are no locks held.
589	 */
590	brd->flipbuf = kzalloc(MYFLIPLEN, GFP_KERNEL);
591
592	wake_up_interruptible(&brd->state_wait);
593
594	return 0;
595
596failed:
597	dgnc_tty_uninit(brd);
598	brd->state = BOARD_FAILED;
599	brd->dpastatus = BD_NOFEP;
600
601	return -ENXIO;
602
603}
604
605
606static int dgnc_finalize_board_init(struct dgnc_board *brd)
607{
608	int rc = 0;
609
610	if (!brd || brd->magic != DGNC_BOARD_MAGIC)
611		return -ENODEV;
612
613	if (brd->irq) {
614		rc = request_irq(brd->irq, brd->bd_ops->intr,
615				 IRQF_SHARED, "DGNC", brd);
616
617		if (rc) {
618			dev_err(&brd->pdev->dev,
619				"Failed to hook IRQ %d\n", brd->irq);
620			brd->state = BOARD_FAILED;
621			brd->dpastatus = BD_NOFEP;
622			rc = -ENODEV;
623		}
624	}
625	return rc;
626}
627
628/*
629 * Remap PCI memory.
630 */
631static void dgnc_do_remap(struct dgnc_board *brd)
632{
633
634	if (!brd || brd->magic != DGNC_BOARD_MAGIC)
635		return;
636
637	brd->re_map_membase = ioremap(brd->membase, 0x1000);
638}
639
640
641/*****************************************************************************
642*
643* Function:
644*
645*    dgnc_poll_handler
646*
647* Author:
648*
649*    Scott H Kilau
650*
651* Parameters:
652*
653*    dummy -- ignored
654*
655* Return Values:
656*
657*    none
658*
659* Description:
660*
661*    As each timer expires, it determines (a) whether the "transmit"
662*    waiter needs to be woken up, and (b) whether the poller needs to
663*    be rescheduled.
664*
665******************************************************************************/
666
667static void dgnc_poll_handler(ulong dummy)
668{
669	struct dgnc_board *brd;
670	unsigned long flags;
671	int i;
672	unsigned long new_time;
673
674	/* Go thru each board, kicking off a tasklet for each if needed */
675	for (i = 0; i < dgnc_NumBoards; i++) {
676		brd = dgnc_Board[i];
677
678		spin_lock_irqsave(&brd->bd_lock, flags);
679
680		/* If board is in a failed state don't schedule a tasklet */
681		if (brd->state == BOARD_FAILED) {
682			spin_unlock_irqrestore(&brd->bd_lock, flags);
683			continue;
684		}
685
686		/* Schedule a poll helper task */
687		tasklet_schedule(&brd->helper_tasklet);
688
689		spin_unlock_irqrestore(&brd->bd_lock, flags);
690	}
691
692	/*
693	 * Schedule ourself back at the nominal wakeup interval.
694	 */
695	spin_lock_irqsave(&dgnc_poll_lock, flags);
696	dgnc_poll_time += dgnc_jiffies_from_ms(dgnc_poll_tick);
697
698	new_time = dgnc_poll_time - jiffies;
699
700	if ((ulong) new_time >= 2 * dgnc_poll_tick)
701		dgnc_poll_time = jiffies + dgnc_jiffies_from_ms(dgnc_poll_tick);
702
703	setup_timer(&dgnc_poll_timer, dgnc_poll_handler, 0);
704	dgnc_poll_timer.expires = dgnc_poll_time;
705	spin_unlock_irqrestore(&dgnc_poll_lock, flags);
706
707	if (!dgnc_poll_stop)
708		add_timer(&dgnc_poll_timer);
709}
710
711/*
712 * dgnc_init_globals()
713 *
714 * This is where we initialize the globals from the static insmod
715 * configuration variables.  These are declared near the head of
716 * this file.
717 */
718static void dgnc_init_globals(void)
719{
720	int i = 0;
721
722	dgnc_NumBoards		= 0;
723
724	for (i = 0; i < MAXBOARDS; i++)
725		dgnc_Board[i] = NULL;
726
727	init_timer(&dgnc_poll_timer);
728}
729
730