/*** (c) 1999 by Computone Corporation*********************************************************************************** PACKAGE: Linux tty Device Driver for IntelliPort family of multiport* serial I/O controllers.** DESCRIPTION: Mainline code for the device driver********************************************************************************/// ToDo://// Fix the immediate DSS_NOW problem.// Work over the channel stats return logic in ip2_ipl_ioctl so they// make sense for all 256 possible channels and so the user space// utilities will compile and work properly.//// Done://// 1.2.14 /\/\|=mhw=|\/\/// Added bounds checking to ip2_ipl_ioctl to avoid potential terroristic acts.// Changed the definition of ip2trace to be more consistent with kernel style// Thanks to Andreas Dilger <adilger@turbolabs.com> for these updates//// 1.2.13 /\/\|=mhw=|\/\/// DEVFS: Renamed ttf/{n} to tts/F{n} and cuf/{n} to cua/F{n} to conform// to agreed devfs serial device naming convention.//// 1.2.12 /\/\|=mhw=|\/\/// Cleaned up some remove queue cut and paste errors//// 1.2.11 /\/\|=mhw=|\/\/// Clean up potential NULL pointer dereferences// Clean up devfs registration// Add kernel command line parsing for io and irq// Compile defaults for io and irq are now set in ip2.c not ip2.h!// Reworked poll_only hack for explicit parameter setting// You must now EXPLICITLY set poll_only = 1 or set all irqs to 0// Merged ip2_loadmain and old_ip2_init// Converted all instances of interruptible_sleep_on into queue calls// Most of these had no race conditions but better to clean up now//// 1.2.10 /\/\|=mhw=|\/\/// Fixed the bottom half interrupt handler and enabled USE_IQI// to split the interrupt handler into a formal top-half / bottom-half// Fixed timing window on high speed processors that queued messages to// the outbound mail fifo faster than the board could handle.//// 1.2.9// Four box EX was barfing on >128k kmalloc, made structure smaller by// reducing output buffer size//// 1.2.8// Device file system support (MHW)//// 1.2.7 // Fixed// Reload of ip2 without unloading ip2main hangs system on cat of /proc/modules//// 1.2.6//Fixes DCD problems// DCD was not reported when CLOCAL was set on call to TIOCMGET////Enhancements:// TIOCMGET requests and waits for status return// No DSS interrupts enabled except for DCD when needed//// For internal use only////#define IP2DEBUG_INIT//#define IP2DEBUG_OPEN//#define IP2DEBUG_WRITE//#define IP2DEBUG_READ//#define IP2DEBUG_IOCTL//#define IP2DEBUG_IPL //#define IP2DEBUG_TRACE//#define DEBUG_FIFO /************//* Includes *//************/ #include <linux/ctype.h>#include <linux/string.h>#include <linux/fcntl.h>#include <linux/errno.h>#include <linux/module.h>#include <linux/signal.h>#include <linux/sched.h>#include <linux/timer.h>#include <linux/interrupt.h>#include <linux/pci.h>#include <linux/mm.h>#include <linux/slab.h>#include <linux/major.h>#include <linux/wait.h>#include <linux/device.h> #include <linux/tty.h>#include <linux/tty_flip.h>#include <linux/termios.h>#include <linux/tty_driver.h>#include <linux/serial.h>#include <linux/ptrace.h>#include <linux/ioport.h> #include <linux/cdk.h>#include <linux/comstats.h>#include <linux/delay.h>#include <linux/bitops.h> #include <asm/system.h>#include <asm/io.h>#include <asm/irq.h> #include <linux/vmalloc.h>#include <linux/init.h> #include <asm/uaccess.h> #include "ip2types.h"#include "ip2trace.h"#include "ip2ioctl.h"#include "ip2.h"#include "i2ellis.h"#include "i2lib.h" /***************** * /proc/ip2mem * *****************/ #include <linux/proc_fs.h> static int ip2_read_procmem(char *, char **, off_t, int);static int ip2_read_proc(char *, char **, off_t, int, int *, void * ); /********************//* Type Definitions *//********************/ /*************//* Constants *//*************/ /* String constants to identify ourselves */static char *pcName = "Computone IntelliPort Plus multiport driver";static char *pcVersion = "1.2.14"; /* String constants for port names */static char *pcDriver_name = "ip2";static char *pcIpl = "ip2ipl"; /* Serial subtype definitions */#define SERIAL_TYPE_NORMAL 1 // cheezy kludge or genius - you decide?int ip2_loadmain(int *, int *, unsigned char *, int);static unsigned char *Fip_firmware;static int Fip_firmware_size; /***********************//* Function Prototypes *//***********************/ /* Global module entry functions */ /* Private (static) functions */static int ip2_open(PTTY, struct file *);static void ip2_close(PTTY, struct file *);static int ip2_write(PTTY, const unsigned char *, int);static void ip2_putchar(PTTY, unsigned char);static void ip2_flush_chars(PTTY);static int ip2_write_room(PTTY);static int ip2_chars_in_buf(PTTY);static void ip2_flush_buffer(PTTY);static int ip2_ioctl(PTTY, struct file *, UINT, ULONG);static void ip2_set_termios(PTTY, struct ktermios *);static void ip2_set_line_discipline(PTTY);static void ip2_throttle(PTTY);static void ip2_unthrottle(PTTY);static void ip2_stop(PTTY);static void ip2_start(PTTY);static void ip2_hangup(PTTY);static int ip2_tiocmget(struct tty_struct *tty, struct file *file);static int ip2_tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear); static void set_irq(int, int);static void ip2_interrupt_bh(struct work_struct *work);static irqreturn_t ip2_interrupt(int irq, void *dev_id);static void ip2_poll(unsigned long arg);static inline void service_all_boards(void);static void do_input(struct work_struct *);static void do_status(struct work_struct *); static void ip2_wait_until_sent(PTTY,int); static void set_params (i2ChanStrPtr, struct ktermios *);static int get_serial_info(i2ChanStrPtr, struct serial_struct __user *);static int set_serial_info(i2ChanStrPtr, struct serial_struct __user *); static ssize_t ip2_ipl_read(struct file *, char __user *, size_t, loff_t *);static ssize_t ip2_ipl_write(struct file *, const char __user *, size_t, loff_t *);static int ip2_ipl_ioctl(struct inode *, struct file *, UINT, ULONG);static int ip2_ipl_open(struct inode *, struct file *); static int DumpTraceBuffer(char __user *, int);static int DumpFifoBuffer( char __user *, int); static void ip2_init_board(int);static unsigned short find_eisa_board(int); /***************//* Static Data *//***************/ static struct tty_driver *ip2_tty_driver; /* Here, then is a table of board pointers which the interrupt routine should * scan through to determine who it must service. */static unsigned short i2nBoards; // Number of boards here static i2eBordStrPtr i2BoardPtrTable[IP2_MAX_BOARDS]; static i2ChanStrPtr DevTable[IP2_MAX_PORTS];//DevTableMem just used to save addresses for kfreestatic void *DevTableMem[IP2_MAX_BOARDS]; /* This is the driver descriptor for the ip2ipl device, which is used to * download the loadware to the boards. */static const struct file_operations ip2_ipl = { .owner = THIS_MODULE, .read = ip2_ipl_read, .write = ip2_ipl_write, .ioctl = ip2_ipl_ioctl, .open = ip2_ipl_open,}; static unsigned long irq_counter = 0;static unsigned long bh_counter = 0; // Use immediate queue to service interrupts#define USE_IQI//#define USE_IQ // PCI&2.2 needs work /* The timer_list entry for our poll routine. If interrupt operation is not * selected, the board is serviced periodically to see if anything needs doing. */#define POLL_TIMEOUT (jiffies + 1)static DEFINE_TIMER(PollTimer, ip2_poll, 0, 0);static char TimerOn; #ifdef IP2DEBUG_TRACE/* Trace (debug) buffer data */#define TRACEMAX 1000static unsigned long tracebuf[TRACEMAX];static int tracestuff;static int tracestrip;static int tracewrap;#endif /**********//* Macros *//**********/ #if defined(MODULE) && defined(IP2DEBUG_OPEN)#define DBG_CNT(s) printk(KERN_DEBUG "(%s): [%x] refc=%d, ttyc=%d, modc=%x -> %s\n", \ tty->name,(pCh->flags),ip2_tty_driver->refcount, \ tty->count,/*GET_USE_COUNT(module)*/0,s)#else#define DBG_CNT(s)#endif /********//* Code *//********/ #include "i2ellis.c" /* Extremely low-level interface services */#include "i2cmd.c" /* Standard loadware command definitions */#include "i2lib.c" /* High level interface services */ /* Configuration area for modprobe */ MODULE_AUTHOR("Doug McNash");MODULE_DESCRIPTION("Computone IntelliPort Plus Driver"); static int poll_only = 0; static int Eisa_irq;static int Eisa_slot; static int iindx;static char rirqs[IP2_MAX_BOARDS];static int Valid_Irqs[] = { 3, 4, 5, 7, 10, 11, 12, 15, 0}; /* for sysfs class support */static struct class *ip2_class; // Some functions to keep track of what irq's we have static intis_valid_irq(int irq){ int *i = Valid_Irqs; while ((*i != 0) && (*i != irq)) { i++; } return (*i);} static voidmark_requested_irq( char irq ){ rirqs[iindx++] = irq;} #ifdef MODULEstatic intclear_requested_irq( char irq ){ int i; for ( i = 0; i < IP2_MAX_BOARDS; ++i ) { if (rirqs[i] == irq) { rirqs[i] = 0; return 1; } } return 0;}#endif static inthave_requested_irq( char irq ){ // array init to zeros so 0 irq will not be requested as a side effect int i; for ( i = 0; i < IP2_MAX_BOARDS; ++i ) { if (rirqs[i] == irq) return 1; } return 0;} /******************************************************************************//* Function: init_module() *//* Parameters: None *//* Returns: Success (0) *//* *//* Description: *//* This is a required entry point for an installable module. It simply calls *//* the driver initialisation function and returns what it returns. *//******************************************************************************/#ifdef MODULEintinit_module(void){#ifdef IP2DEBUG_INIT printk (KERN_DEBUG "Loading module ...\n" );#endif return 0;}#endif /* MODULE */ /******************************************************************************//* Function: cleanup_module() *//* Parameters: None *//* Returns: Nothing *//* *//* Description: *//* This is a required entry point for an installable module. It has to return *//* the device and the driver to a passive state. It should not be necessary *//* to reset the board fully, especially as the loadware is downloaded *//* externally rather than in the driver. We just want to disable the board *//* and clear the loadware to a reset state. To allow this there has to be a *//* way to detect whether the board has the loadware running at init time to *//* handle subsequent installations of the driver. All memory allocated by the *//* driver should be returned since it may be unloaded from memory. *//******************************************************************************/#ifdef MODULEvoidcleanup_module(void){ int err; int i; #ifdef IP2DEBUG_INIT printk (KERN_DEBUG "Unloading %s: version %s\n", pcName, pcVersion );#endif /* Stop poll timer if we had one. */ if ( TimerOn ) { del_timer ( &PollTimer ); TimerOn = 0; } /* Reset the boards we have. */ for( i = 0; i < IP2_MAX_BOARDS; ++i ) { if ( i2BoardPtrTable[i] ) { iiReset( i2BoardPtrTable[i] ); } } /* The following is done at most once, if any boards were installed. */ for ( i = 0; i < IP2_MAX_BOARDS; ++i ) { if ( i2BoardPtrTable[i] ) { iiResetDelay( i2BoardPtrTable[i] ); /* free io addresses and Tibet */ release_region( ip2config.addr[i], 8 ); class_device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i)); class_device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i + 1)); } /* Disable and remove interrupt handler. */ if ( (ip2config.irq[i] > 0) && have_requested_irq(ip2config.irq[i]) ) { free_irq ( ip2config.irq[i], (void *)&pcName); clear_requested_irq( ip2config.irq[i]); } } class_destroy(ip2_class); if ( ( err = tty_unregister_driver ( ip2_tty_driver ) ) ) { printk(KERN_ERR "IP2: failed to unregister tty driver (%d)\n", err); } put_tty_driver(ip2_tty_driver); if ( ( err = unregister_chrdev ( IP2_IPL_MAJOR, pcIpl ) ) ) { printk(KERN_ERR "IP2: failed to unregister IPL driver (%d)\n", err); } remove_proc_entry("ip2mem", &proc_root); // free memory for (i = 0; i < IP2_MAX_BOARDS; i++) { void *pB;#ifdef CONFIG_PCI if (ip2config.type[i] == PCI && ip2config.pci_dev[i]) { pci_disable_device(ip2config.pci_dev[i]); pci_dev_put(ip2config.pci_dev[i]); ip2config.pci_dev[i] = NULL; }#endif if ((pB = i2BoardPtrTable[i]) != 0 ) { kfree ( pB ); i2BoardPtrTable[i] = NULL; } if ((DevTableMem[i]) != NULL ) { kfree ( DevTableMem[i] ); DevTableMem[i] = NULL; } } /* Cleanup the iiEllis subsystem. */ iiEllisCleanup();#ifdef IP2DEBUG_INIT printk (KERN_DEBUG "IP2 Unloaded\n" );#endif}#endif /* MODULE */ static const struct tty_operations ip2_ops = { .open = ip2_open, .close = ip2_close, .write = ip2_write, .put_char = ip2_putchar, .flush_chars = ip2_flush_chars, .write_room = ip2_write_room, .chars_in_buffer = ip2_chars_in_buf, .flush_buffer = ip2_flush_buffer, .ioctl = ip2_ioctl, .throttle = ip2_throttle, .unthrottle = ip2_unthrottle, .set_termios = ip2_set_termios, .set_ldisc = ip2_set_line_discipline, .stop = ip2_stop, .start = ip2_start, .hangup = ip2_hangup, .read_proc = ip2_read_proc, .tiocmget = ip2_tiocmget, .tiocmset = ip2_tiocmset,}; /******************************************************************************//* Function: ip2_loadmain() *//* Parameters: irq, io from command line of insmod et. al. *//* pointer to fip firmware and firmware size for boards *//* Returns: Success (0) *//* *//* Description: *//* This was the required entry point for all drivers (now in ip2.c) *//* It performs all *//* initialisation of the devices and driver structures, and registers itself *//* with the relevant kernel modules. *//******************************************************************************//* IRQF_DISABLED - if set blocks all interrupts else only this line *//* IRQF_SHARED - for shared irq PCI or maybe EISA only *//* SA_RANDOM - can be source for cert. random number generators */#define IP2_SA_FLAGS 0 intLines 1–500 of 3197. Load more
/* * * (c) 1999 by Computone Corporation * ******************************************************************************** * * PACKAGE: Linux tty Device Driver for IntelliPort family of multiport * serial I/O controllers. * * DESCRIPTION: Mainline code for the device driver * *******************************************************************************/ // ToDo: // // Fix the immediate DSS_NOW problem. // Work over the channel stats return logic in ip2_ipl_ioctl so they // make sense for all 256 possible channels and so the user space // utilities will compile and work properly. // // Done: // // 1.2.14 /\/\|=mhw=|\/\/ // Added bounds checking to ip2_ipl_ioctl to avoid potential terroristic acts. // Changed the definition of ip2trace to be more consistent with kernel style // Thanks to Andreas Dilger <adilger@turbolabs.com> for these updates // // 1.2.13 /\/\|=mhw=|\/\/ // DEVFS: Renamed ttf/{n} to tts/F{n} and cuf/{n} to cua/F{n} to conform // to agreed devfs serial device naming convention. // // 1.2.12 /\/\|=mhw=|\/\/ // Cleaned up some remove queue cut and paste errors // // 1.2.11 /\/\|=mhw=|\/\/ // Clean up potential NULL pointer dereferences // Clean up devfs registration // Add kernel command line parsing for io and irq // Compile defaults for io and irq are now set in ip2.c not ip2.h! // Reworked poll_only hack for explicit parameter setting // You must now EXPLICITLY set poll_only = 1 or set all irqs to 0 // Merged ip2_loadmain and old_ip2_init // Converted all instances of interruptible_sleep_on into queue calls // Most of these had no race conditions but better to clean up now // // 1.2.10 /\/\|=mhw=|\/\/ // Fixed the bottom half interrupt handler and enabled USE_IQI // to split the interrupt handler into a formal top-half / bottom-half // Fixed timing window on high speed processors that queued messages to // the outbound mail fifo faster than the board could handle. // // 1.2.9 // Four box EX was barfing on >128k kmalloc, made structure smaller by // reducing output buffer size // // 1.2.8 // Device file system support (MHW) // // 1.2.7 // Fixed // Reload of ip2 without unloading ip2main hangs system on cat of /proc/modules // // 1.2.6 //Fixes DCD problems // DCD was not reported when CLOCAL was set on call to TIOCMGET // //Enhancements: // TIOCMGET requests and waits for status return // No DSS interrupts enabled except for DCD when needed // // For internal use only // //#define IP2DEBUG_INIT //#define IP2DEBUG_OPEN //#define IP2DEBUG_WRITE //#define IP2DEBUG_READ //#define IP2DEBUG_IOCTL //#define IP2DEBUG_IPL //#define IP2DEBUG_TRACE //#define DEBUG_FIFO /************/ /* Includes */ /************/ #include <linux/ctype.h> #include <linux/string.h> #include <linux/fcntl.h> #include <linux/errno.h> #include <linux/module.h> #include <linux/signal.h> #include <linux/sched.h> #include <linux/timer.h> #include <linux/interrupt.h> #include <linux/pci.h> #include <linux/mm.h> #include <linux/slab.h> #include <linux/major.h> #include <linux/wait.h> #include <linux/device.h> #include <linux/tty.h> #include <linux/tty_flip.h> #include <linux/termios.h> #include <linux/tty_driver.h> #include <linux/serial.h> #include <linux/ptrace.h> #include <linux/ioport.h> #include <linux/cdk.h> #include <linux/comstats.h> #include <linux/delay.h> #include <linux/bitops.h> #include <asm/system.h> #include <asm/io.h> #include <asm/irq.h> #include <linux/vmalloc.h> #include <linux/init.h> #include <asm/uaccess.h> #include "ip2types.h" #include "ip2trace.h" #include "ip2ioctl.h" #include "ip2.h" #include "i2ellis.h" #include "i2lib.h" /***************** * /proc/ip2mem * *****************/ #include <linux/proc_fs.h> static int ip2_read_procmem(char *, char **, off_t, int); static int ip2_read_proc(char *, char **, off_t, int, int *, void * ); /********************/ /* Type Definitions */ /********************/ /*************/ /* Constants */ /*************/ /* String constants to identify ourselves */ static char *pcName = "Computone IntelliPort Plus multiport driver"; static char *pcVersion = "1.2.14"; /* String constants for port names */ static char *pcDriver_name = "ip2"; static char *pcIpl = "ip2ipl"; /* Serial subtype definitions */ #define SERIAL_TYPE_NORMAL 1 // cheezy kludge or genius - you decide? int ip2_loadmain(int *, int *, unsigned char *, int); static unsigned char *Fip_firmware; static int Fip_firmware_size; /***********************/ /* Function Prototypes */ /***********************/ /* Global module entry functions */ /* Private (static) functions */ static int ip2_open(PTTY, struct file *); static void ip2_close(PTTY, struct file *); static int ip2_write(PTTY, const unsigned char *, int); static void ip2_putchar(PTTY, unsigned char); static void ip2_flush_chars(PTTY); static int ip2_write_room(PTTY); static int ip2_chars_in_buf(PTTY); static void ip2_flush_buffer(PTTY); static int ip2_ioctl(PTTY, struct file *, UINT, ULONG); static void ip2_set_termios(PTTY, struct ktermios *); static void ip2_set_line_discipline(PTTY); static void ip2_throttle(PTTY); static void ip2_unthrottle(PTTY); static void ip2_stop(PTTY); static void ip2_start(PTTY); static void ip2_hangup(PTTY); static int ip2_tiocmget(struct tty_struct *tty, struct file *file); static int ip2_tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear); static void set_irq(int, int); static void ip2_interrupt_bh(struct work_struct *work); static irqreturn_t ip2_interrupt(int irq, void *dev_id); static void ip2_poll(unsigned long arg); static inline void service_all_boards(void); static void do_input(struct work_struct *); static void do_status(struct work_struct *); static void ip2_wait_until_sent(PTTY,int); static void set_params (i2ChanStrPtr, struct ktermios *); static int get_serial_info(i2ChanStrPtr, struct serial_struct __user *); static int set_serial_info(i2ChanStrPtr, struct serial_struct __user *); static ssize_t ip2_ipl_read(struct file *, char __user *, size_t, loff_t *); static ssize_t ip2_ipl_write(struct file *, const char __user *, size_t, loff_t *); static int ip2_ipl_ioctl(struct inode *, struct file *, UINT, ULONG); static int ip2_ipl_open(struct inode *, struct file *); static int DumpTraceBuffer(char __user *, int); static int DumpFifoBuffer( char __user *, int); static void ip2_init_board(int); static unsigned short find_eisa_board(int); /***************/ /* Static Data */ /***************/ static struct tty_driver *ip2_tty_driver; /* Here, then is a table of board pointers which the interrupt routine should * scan through to determine who it must service. */ static unsigned short i2nBoards; // Number of boards here static i2eBordStrPtr i2BoardPtrTable[IP2_MAX_BOARDS]; static i2ChanStrPtr DevTable[IP2_MAX_PORTS]; //DevTableMem just used to save addresses for kfree static void *DevTableMem[IP2_MAX_BOARDS]; /* This is the driver descriptor for the ip2ipl device, which is used to * download the loadware to the boards. */ static const struct file_operations ip2_ipl = { .owner = THIS_MODULE, .read = ip2_ipl_read, .write = ip2_ipl_write, .ioctl = ip2_ipl_ioctl, .open = ip2_ipl_open, }; static unsigned long irq_counter = 0; static unsigned long bh_counter = 0; // Use immediate queue to service interrupts #define USE_IQI //#define USE_IQ // PCI&2.2 needs work /* The timer_list entry for our poll routine. If interrupt operation is not * selected, the board is serviced periodically to see if anything needs doing. */ #define POLL_TIMEOUT (jiffies + 1) static DEFINE_TIMER(PollTimer, ip2_poll, 0, 0); static char TimerOn; #ifdef IP2DEBUG_TRACE /* Trace (debug) buffer data */ #define TRACEMAX 1000 static unsigned long tracebuf[TRACEMAX]; static int tracestuff; static int tracestrip; static int tracewrap; #endif /**********/ /* Macros */ /**********/ #if defined(MODULE) && defined(IP2DEBUG_OPEN) #define DBG_CNT(s) printk(KERN_DEBUG "(%s): [%x] refc=%d, ttyc=%d, modc=%x -> %s\n", \ tty->name,(pCh->flags),ip2_tty_driver->refcount, \ tty->count,/*GET_USE_COUNT(module)*/0,s) #else #define DBG_CNT(s) #endif /********/ /* Code */ /********/ #include "i2ellis.c" /* Extremely low-level interface services */ #include "i2cmd.c" /* Standard loadware command definitions */ #include "i2lib.c" /* High level interface services */ /* Configuration area for modprobe */ MODULE_AUTHOR("Doug McNash"); MODULE_DESCRIPTION("Computone IntelliPort Plus Driver"); static int poll_only = 0; static int Eisa_irq; static int Eisa_slot; static int iindx; static char rirqs[IP2_MAX_BOARDS]; static int Valid_Irqs[] = { 3, 4, 5, 7, 10, 11, 12, 15, 0}; /* for sysfs class support */ static struct class *ip2_class; // Some functions to keep track of what irq's we have static int is_valid_irq(int irq) { int *i = Valid_Irqs; while ((*i != 0) && (*i != irq)) { i++; } return (*i); } static void mark_requested_irq( char irq ) { rirqs[iindx++] = irq; } #ifdef MODULE static int clear_requested_irq( char irq ) { int i; for ( i = 0; i < IP2_MAX_BOARDS; ++i ) { if (rirqs[i] == irq) { rirqs[i] = 0; return 1; } } return 0; } #endif static int have_requested_irq( char irq ) { // array init to zeros so 0 irq will not be requested as a side effect int i; for ( i = 0; i < IP2_MAX_BOARDS; ++i ) { if (rirqs[i] == irq) return 1; } return 0; } /******************************************************************************/ /* Function: init_module() */ /* Parameters: None */ /* Returns: Success (0) */ /* */ /* Description: */ /* This is a required entry point for an installable module. It simply calls */ /* the driver initialisation function and returns what it returns. */ /******************************************************************************/ #ifdef MODULE int init_module(void) { #ifdef IP2DEBUG_INIT printk (KERN_DEBUG "Loading module ...\n" ); #endif return 0; } #endif /* MODULE */ /******************************************************************************/ /* Function: cleanup_module() */ /* Parameters: None */ /* Returns: Nothing */ /* */ /* Description: */ /* This is a required entry point for an installable module. It has to return */ /* the device and the driver to a passive state. It should not be necessary */ /* to reset the board fully, especially as the loadware is downloaded */ /* externally rather than in the driver. We just want to disable the board */ /* and clear the loadware to a reset state. To allow this there has to be a */ /* way to detect whether the board has the loadware running at init time to */ /* handle subsequent installations of the driver. All memory allocated by the */ /* driver should be returned since it may be unloaded from memory. */ /******************************************************************************/ #ifdef MODULE void cleanup_module(void) { int err; int i; #ifdef IP2DEBUG_INIT printk (KERN_DEBUG "Unloading %s: version %s\n", pcName, pcVersion ); #endif /* Stop poll timer if we had one. */ if ( TimerOn ) { del_timer ( &PollTimer ); TimerOn = 0; } /* Reset the boards we have. */ for( i = 0; i < IP2_MAX_BOARDS; ++i ) { if ( i2BoardPtrTable[i] ) { iiReset( i2BoardPtrTable[i] ); } } /* The following is done at most once, if any boards were installed. */ for ( i = 0; i < IP2_MAX_BOARDS; ++i ) { if ( i2BoardPtrTable[i] ) { iiResetDelay( i2BoardPtrTable[i] ); /* free io addresses and Tibet */ release_region( ip2config.addr[i], 8 ); class_device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i)); class_device_destroy(ip2_class, MKDEV(IP2_IPL_MAJOR, 4 * i + 1)); } /* Disable and remove interrupt handler. */ if ( (ip2config.irq[i] > 0) && have_requested_irq(ip2config.irq[i]) ) { free_irq ( ip2config.irq[i], (void *)&pcName); clear_requested_irq( ip2config.irq[i]); } } class_destroy(ip2_class); if ( ( err = tty_unregister_driver ( ip2_tty_driver ) ) ) { printk(KERN_ERR "IP2: failed to unregister tty driver (%d)\n", err); } put_tty_driver(ip2_tty_driver); if ( ( err = unregister_chrdev ( IP2_IPL_MAJOR, pcIpl ) ) ) { printk(KERN_ERR "IP2: failed to unregister IPL driver (%d)\n", err); } remove_proc_entry("ip2mem", &proc_root); // free memory for (i = 0; i < IP2_MAX_BOARDS; i++) { void *pB; #ifdef CONFIG_PCI if (ip2config.type[i] == PCI && ip2config.pci_dev[i]) { pci_disable_device(ip2config.pci_dev[i]); pci_dev_put(ip2config.pci_dev[i]); ip2config.pci_dev[i] = NULL; } #endif if ((pB = i2BoardPtrTable[i]) != 0 ) { kfree ( pB ); i2BoardPtrTable[i] = NULL; } if ((DevTableMem[i]) != NULL ) { kfree ( DevTableMem[i] ); DevTableMem[i] = NULL; } } /* Cleanup the iiEllis subsystem. */ iiEllisCleanup(); #ifdef IP2DEBUG_INIT printk (KERN_DEBUG "IP2 Unloaded\n" ); #endif } #endif /* MODULE */ static const struct tty_operations ip2_ops = { .open = ip2_open, .close = ip2_close, .write = ip2_write, .put_char = ip2_putchar, .flush_chars = ip2_flush_chars, .write_room = ip2_write_room, .chars_in_buffer = ip2_chars_in_buf, .flush_buffer = ip2_flush_buffer, .ioctl = ip2_ioctl, .throttle = ip2_throttle, .unthrottle = ip2_unthrottle, .set_termios = ip2_set_termios, .set_ldisc = ip2_set_line_discipline, .stop = ip2_stop, .start = ip2_start, .hangup = ip2_hangup, .read_proc = ip2_read_proc, .tiocmget = ip2_tiocmget, .tiocmset = ip2_tiocmset, }; /******************************************************************************/ /* Function: ip2_loadmain() */ /* Parameters: irq, io from command line of insmod et. al. */ /* pointer to fip firmware and firmware size for boards */ /* Returns: Success (0) */ /* */ /* Description: */ /* This was the required entry point for all drivers (now in ip2.c) */ /* It performs all */ /* initialisation of the devices and driver structures, and registers itself */ /* with the relevant kernel modules. */ /******************************************************************************/ /* IRQF_DISABLED - if set blocks all interrupts else only this line */ /* IRQF_SHARED - for shared irq PCI or maybe EISA only */ /* SA_RANDOM - can be source for cert. random number generators */ #define IP2_SA_FLAGS 0 int