📄 sdlamain.c
字号:
/***************************************************************************** sdlamain.c WANPIPE(tm) Multiprotocol WAN Link Driver. Main module.** Author: Nenad Corbic <ncorbic@sangoma.com>* Gideon Hack ** Copyright: (c) 1995-2000 Sangoma Technologies Inc.** This program is free software; you can redistribute it and/or* modify it under the terms of the GNU General Public License* as published by the Free Software Foundation; either version* 2 of the License, or (at your option) any later version.* ============================================================================* Dec 22, 2000 Nenad Corbic Updated for 2.4.X kernels.* Removed the polling routine.* Nov 13, 2000 Nenad Corbic Added hw probing on module load and dynamic* device allocation. * Nov 7, 2000 Nenad Corbic Fixed the Multi-Port PPP for kernels* 2.2.16 and above.* Aug 2, 2000 Nenad Corbic Block the Multi-Port PPP from running on* kernels 2.2.16 or greater. The SyncPPP * has changed.* Jul 25, 2000 Nenad Corbic Updated the Piggiback support for MultPPPP.* Jul 13, 2000 Nenad Corbic Added Multi-PPP support.* Feb 02, 2000 Nenad Corbic Fixed up piggyback probing and selection.* Sep 23, 1999 Nenad Corbic Added support for SMP* Sep 13, 1999 Nenad Corbic Each port is treated as a separate device.* Jun 02, 1999 Gideon Hack Added support for the S514 adapter.* Updates for Linux 2.2.X kernels.* Sep 17, 1998 Jaspreet Singh Updated for 2.1.121+ kernel* Nov 28, 1997 Jaspreet Singh Changed DRV_RELEASE to 1* Nov 10, 1997 Jaspreet Singh Changed sti() to restore_flags();* Nov 06, 1997 Jaspreet Singh Changed DRV_VERSION to 4 and DRV_RELEASE to 0* Oct 20, 1997 Jaspreet Singh Modified sdla_isr routine so that card->in_isr* assignments are taken out and placed in the* sdla_ppp.c, sdla_fr.c and sdla_x25.c isr* routines. Took out 'wandev->tx_int_enabled' and* replaced it with 'wandev->enable_tx_int'. * May 29, 1997 Jaspreet Singh Flow Control Problem* added "wandev->tx_int_enabled=1" line in the* init module. This line initializes the flag for * preventing Interrupt disabled with device set to* busy* Jan 15, 1997 Gene Kozin Version 3.1.0* o added UDP management stuff* Jan 02, 1997 Gene Kozin Initial version.*****************************************************************************/#include <linux/config.h> /* OS configuration options */#include <linux/stddef.h> /* offsetof(), etc. */#include <linux/errno.h> /* return codes */#include <linux/string.h> /* inline memset(), etc. */#include <linux/init.h>#include <linux/slab.h> /* kmalloc(), kfree() */#include <linux/kernel.h> /* printk(), and other useful stuff */#include <linux/module.h> /* support for loadable modules */#include <linux/ioport.h> /* request_region(), release_region() */#include <linux/wanrouter.h> /* WAN router definitions */#include <linux/wanpipe.h> /* WANPIPE common user API definitions */#include <linux/rcupdate.h>#include <linux/in.h>#include <asm/io.h> /* phys_to_virt() */#include <linux/pci.h>#include <linux/sdlapci.h>#include <linux/if_wanpipe_common.h>#include <asm/uaccess.h> /* kernel <-> user copy */#include <linux/inetdevice.h>#include <linux/ip.h>#include <net/route.h> #define KMEM_SAFETYZONE 8#ifndef CONFIG_WANPIPE_FR #define wpf_init(a,b) (-EPROTONOSUPPORT) #endif#ifndef CONFIG_WANPIPE_CHDLC #define wpc_init(a,b) (-EPROTONOSUPPORT) #endif#ifndef CONFIG_WANPIPE_X25 #define wpx_init(a,b) (-EPROTONOSUPPORT) #endif #ifndef CONFIG_WANPIPE_PPP #define wpp_init(a,b) (-EPROTONOSUPPORT) #endif#ifndef CONFIG_WANPIPE_MULTPPP #define wsppp_init(a,b) (-EPROTONOSUPPORT) #endif /***********FOR DEBUGGING PURPOSES*********************************************static void * dbg_kmalloc(unsigned int size, int prio, int line) { int i = 0; void * v = kmalloc(size+sizeof(unsigned int)+2*KMEM_SAFETYZONE*8,prio); char * c1 = v; c1 += sizeof(unsigned int); *((unsigned int *)v) = size; for (i = 0; i < KMEM_SAFETYZONE; i++) { c1[0] = 'D'; c1[1] = 'E'; c1[2] = 'A'; c1[3] = 'D'; c1[4] = 'B'; c1[5] = 'E'; c1[6] = 'E'; c1[7] = 'F'; c1 += 8; } c1 += size; for (i = 0; i < KMEM_SAFETYZONE; i++) { c1[0] = 'M'; c1[1] = 'U'; c1[2] = 'N'; c1[3] = 'G'; c1[4] = 'W'; c1[5] = 'A'; c1[6] = 'L'; c1[7] = 'L'; c1 += 8; } v = ((char *)v) + sizeof(unsigned int) + KMEM_SAFETYZONE*8; printk(KERN_INFO "line %d kmalloc(%d,%d) = %p\n",line,size,prio,v); return v;}static void dbg_kfree(void * v, int line) { unsigned int * sp = (unsigned int *)(((char *)v) - (sizeof(unsigned int) + KMEM_SAFETYZONE*8)); unsigned int size = *sp; char * c1 = ((char *)v) - KMEM_SAFETYZONE*8; int i = 0; for (i = 0; i < KMEM_SAFETYZONE; i++) { if ( c1[0] != 'D' || c1[1] != 'E' || c1[2] != 'A' || c1[3] != 'D' || c1[4] != 'B' || c1[5] != 'E' || c1[6] != 'E' || c1[7] != 'F') { printk(KERN_INFO "kmalloced block at %p has been corrupted (underrun)!\n",v); printk(KERN_INFO " %4x: %2x %2x %2x %2x %2x %2x %2x %2x\n", i*8, c1[0],c1[1],c1[2],c1[3],c1[4],c1[5],c1[6],c1[7] ); } c1 += 8; } c1 += size; for (i = 0; i < KMEM_SAFETYZONE; i++) { if ( c1[0] != 'M' || c1[1] != 'U' || c1[2] != 'N' || c1[3] != 'G' || c1[4] != 'W' || c1[5] != 'A' || c1[6] != 'L' || c1[7] != 'L' ) { printk(KERN_INFO "kmalloced block at %p has been corrupted (overrun):\n",v); printk(KERN_INFO " %4x: %2x %2x %2x %2x %2x %2x %2x %2x\n", i*8, c1[0],c1[1],c1[2],c1[3],c1[4],c1[5],c1[6],c1[7] ); } c1 += 8; } printk(KERN_INFO "line %d kfree(%p)\n",line,v); v = ((char *)v) - (sizeof(unsigned int) + KMEM_SAFETYZONE*8); kfree(v);}#define kmalloc(x,y) dbg_kmalloc(x,y,__LINE__)#define kfree(x) dbg_kfree(x,__LINE__)******************************************************************************//****** Defines & Macros ****************************************************/#ifdef _DEBUG_#define STATIC#else#define STATIC static#endif#define DRV_VERSION 5 /* version number */#define DRV_RELEASE 0 /* release (minor version) number */#define MAX_CARDS 16 /* max number of adapters */#ifndef CONFIG_WANPIPE_CARDS /* configurable option */#define CONFIG_WANPIPE_CARDS 1#endif#define CMD_OK 0 /* normal firmware return code */#define CMD_TIMEOUT 0xFF /* firmware command timed out */#define MAX_CMD_RETRY 10 /* max number of firmware retries *//****** Function Prototypes *************************************************/extern void disable_irq(unsigned int);extern void enable_irq(unsigned int); /* WAN link driver entry points */static int setup(struct wan_device* wandev, wandev_conf_t* conf);static int shutdown(struct wan_device* wandev);static int ioctl(struct wan_device* wandev, unsigned cmd, unsigned long arg);/* IOCTL handlers */static int ioctl_dump (sdla_t* card, sdla_dump_t* u_dump);static int ioctl_exec (sdla_t* card, sdla_exec_t* u_exec, int);/* Miscellaneous functions */STATIC irqreturn_t sdla_isr (int irq, void* dev_id, struct pt_regs *regs);static void release_hw (sdla_t *card);static int check_s508_conflicts (sdla_t* card,wandev_conf_t* conf, int*);static int check_s514_conflicts (sdla_t* card,wandev_conf_t* conf, int*);/****** Global Data ********************************************************** * Note: All data must be explicitly initialized!!! *//* private data */static char drvname[] = "wanpipe";static char fullname[] = "WANPIPE(tm) Multiprotocol Driver";static char copyright[] = "(c) 1995-2000 Sangoma Technologies Inc.";static int ncards; static sdla_t* card_array; /* adapter data space *//* Wanpipe's own workqueue, used for all API's. * All protocol specific tasks will be inserted * into the "wanpipe_wq" workqueue. * The kernel workqueue mechanism will execute * all pending tasks in the "wanpipe_wq" workqueue. */struct workqueue_struct *wanpipe_wq;DECLARE_WORK(wanpipe_work, NULL, NULL);static int wanpipe_bh_critical;/******* Kernel Loadable Module Entry Points ********************************//*============================================================================ * Module 'insert' entry point. * o print announcement * o allocate adapter data space * o initialize static data * o register all cards with WAN router * o calibrate SDLA shared memory access delay. * * Return: 0 Ok * < 0 error. * Context: process */ static int __init wanpipe_init(void){ int cnt, err = 0; printk(KERN_INFO "%s v%u.%u %s\n", fullname, DRV_VERSION, DRV_RELEASE, copyright); wanpipe_wq = create_workqueue("wanpipe_wq"); if (!wanpipe_wq) return -ENOMEM; /* Probe for wanpipe cards and return the number found */ printk(KERN_INFO "wanpipe: Probing for WANPIPE hardware.\n"); ncards = wanpipe_hw_probe(); if (ncards){ printk(KERN_INFO "wanpipe: Allocating maximum %i devices: wanpipe%i - wanpipe%i.\n",ncards,1,ncards); }else{ printk(KERN_INFO "wanpipe: No S514/S508 cards found, unloading modules!\n"); destroy_workqueue(wanpipe_wq); return -ENODEV; } /* Verify number of cards and allocate adapter data space */ card_array = kmalloc(sizeof(sdla_t) * ncards, GFP_KERNEL); if (card_array == NULL) { destroy_workqueue(wanpipe_wq); return -ENOMEM; } memset(card_array, 0, sizeof(sdla_t) * ncards); /* Register adapters with WAN router */ for (cnt = 0; cnt < ncards; ++ cnt) { sdla_t* card = &card_array[cnt]; struct wan_device* wandev = &card->wandev; card->next = NULL; sprintf(card->devname, "%s%d", drvname, cnt + 1); wandev->magic = ROUTER_MAGIC; wandev->name = card->devname; wandev->private = card; wandev->enable_tx_int = 0; wandev->setup = &setup; wandev->shutdown = &shutdown; wandev->ioctl = &ioctl; err = register_wan_device(wandev); if (err) { printk(KERN_INFO "%s: %s registration failed with error %d!\n", drvname, card->devname, err); break; } } if (cnt){ ncards = cnt; /* adjust actual number of cards */ }else { kfree(card_array); destroy_workqueue(wanpipe_wq); printk(KERN_INFO "IN Init Module: NO Cards registered\n"); err = -ENODEV; } return err;}/*============================================================================ * Module 'remove' entry point. * o unregister all adapters from the WAN router * o release all remaining system resources */static void __exit wanpipe_cleanup(void){ int i; if (!ncards) return; for (i = 0; i < ncards; ++i) { sdla_t* card = &card_array[i]; unregister_wan_device(card->devname); } destroy_workqueue(wanpipe_wq); kfree(card_array); printk(KERN_INFO "\nwanpipe: WANPIPE Modules Unloaded.\n");}module_init(wanpipe_init);module_exit(wanpipe_cleanup);/******* WAN Device Driver Entry Points *************************************//*============================================================================ * Setup/configure WAN link driver. * o check adapter state * o make sure firmware is present in configuration * o make sure I/O port and IRQ are specified * o make sure I/O region is available * o allocate interrupt vector * o setup SDLA hardware * o call appropriate routine to perform protocol-specific initialization * o mark I/O region as used * o if this is the first active card, then schedule background task * * This function is called when router handles ROUTER_SETUP IOCTL. The * configuration structure is in kernel memory (including extended data, if * any). */ static int setup(struct wan_device* wandev, wandev_conf_t* conf){ sdla_t* card; int err = 0; int irq=0; /* Sanity checks */ if ((wandev == NULL) || (wandev->private == NULL) || (conf == NULL)){ printk(KERN_INFO "%s: Failed Sdlamain Setup wandev %u, card %u, conf %u !\n", wandev->name, (unsigned int)wandev,(unsigned int)wandev->private, (unsigned int)conf); return -EFAULT; } printk(KERN_INFO "%s: Starting WAN Setup\n", wandev->name); card = wandev->private; if (wandev->state != WAN_UNCONFIGURED){ printk(KERN_INFO "%s: failed sdlamain setup, busy!\n", wandev->name); return -EBUSY; /* already configured */ } printk(KERN_INFO "\nProcessing WAN device %s...\n", wandev->name); /* Initialize the counters for each wandev * Used for counting number of times new_if and * del_if get called. */ wandev->del_if_cnt = 0; wandev->new_if_cnt = 0; wandev->config_id = conf->config_id; if (!conf->data_size || (conf->data == NULL)) { printk(KERN_INFO "%s: firmware not found in configuration data!\n", wandev->name); return -EINVAL; } /* Check for resource conflicts and setup the * card for piggibacking if necessary */ if(!conf->S514_CPU_no[0]) { if ((err=check_s508_conflicts(card,conf,&irq)) != 0){ return err; } }else { if ((err=check_s514_conflicts(card,conf,&irq)) != 0){ return err; } } /* If the current card has already been configured * or it's a piggyback card, do not try to allocate * resources. */ if (!card->wandev.piggyback && !card->configured){ /* Configure hardware, load firmware, etc. */ memset(&card->hw, 0, sizeof(sdlahw_t)); /* for an S514 adapter, pass the CPU number and the slot number read */ /* from 'router.conf' to the 'sdla_setup()' function via the 'port' */ /* parameter */ if (conf->S514_CPU_no[0]){ card->hw.S514_cpu_no[0] = conf->S514_CPU_no[0]; card->hw.S514_slot_no = conf->PCI_slot_no; card->hw.auto_pci_cfg = conf->auto_pci_cfg; if (card->hw.auto_pci_cfg == WANOPT_YES){ printk(KERN_INFO "%s: Setting CPU to %c and Slot to Auto\n", card->devname, card->hw.S514_cpu_no[0]); }else{ printk(KERN_INFO "%s: Setting CPU to %c and Slot to %i\n", card->devname, card->hw.S514_cpu_no[0], card->hw.S514_slot_no); } }else{ /* 508 Card io port and irq initialization */ card->hw.port = conf->ioport; card->hw.irq = (conf->irq == 9) ? 2 : conf->irq; } /* Compute the virtual address of the card in kernel space */ if(conf->maddr){ card->hw.dpmbase = phys_to_virt(conf->maddr); }else{ card->hw.dpmbase = (void *)conf->maddr; } card->hw.dpmsize = SDLA_WINDOWSIZE; /* set the adapter type if using an S514 adapter */ card->hw.type = (conf->S514_CPU_no[0]) ? SDLA_S514 : conf->hw_opt[0]; card->hw.pclk = conf->hw_opt[1]; err = sdla_setup(&card->hw, conf->data, conf->data_size); if (err){ printk(KERN_INFO "%s: Hardware setup Failed %i\n", card->devname,err);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -