3197 lines · 102.0 KB · C
RawDownload
/***   (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 int

Lines 1–500 of 3197.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t