epca.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,180 行 · 第 1/5 页

C
2,180
字号
			printk(KERN_ERR "<Error> - pc_open: Invalid number of ports specified in LILO command\n");		if (setup_error_code & INVALID_MEM_BASE)			printk(KERN_ERR "<Error> - pc_open: Invalid board memory address specified in LILO command\n");		if (setup_error_code & INVALID_PORT_BASE)			printk(KERN_ERR "<Error> - pc_open: Invalid board port address specified in LILO command\n");		if (setup_error_code & INVALID_BOARD_STATUS)			printk(KERN_ERR "<Error> - pc_open: Invalid board status specified in LILO command\n");		if (setup_error_code & INVALID_ALTPIN)			printk(KERN_ERR "<Error> - pc_open: Invalid board altpin specified in LILO command\n");		tty->driver_data = NULL;   /* Mark this device as 'down' */		return(-ENODEV);	}	if ((boardnum >= num_cards) || (boards[boardnum].status == DISABLED)) 	{		tty->driver_data = NULL;   /* Mark this device as 'down' */		return(-ENODEV);	}		if (( bc = ch->brdchan) == 0) 	{		tty->driver_data = NULL;		return(-ENODEV);	}	/* ------------------------------------------------------------------		Every time a channel is opened, increment a counter.  This is 		necessary because we do not wish to flush and shutdown the channel		until the last app holding the channel open, closes it.	 		--------------------------------------------------------------------- */	ch->count++;	/* ----------------------------------------------------------------		Set a kernel structures pointer to our local channel 		structure.  This way we can get to it when passed only		a tty struct.	------------------------------------------------------------------ */	tty->driver_data = ch;		/* ----------------------------------------------------------------		If this is the first time the channel has been opened, initialize		the tty->termios struct otherwise let pc_close handle it.	-------------------------------------------------------------------- */	save_flags(flags);	cli();	globalwinon(ch);	ch->statusflags = 0;	/* Save boards current modem status */	ch->imodem = bc->mstat;	/* ----------------------------------------------------------------	   Set receive head and tail ptrs to each other.  This indicates	   no data available to read.	----------------------------------------------------------------- */	head = bc->rin;	bc->rout = head;	/* Set the channels associated tty structure */	ch->tty = tty;	/* -----------------------------------------------------------------		The below routine generally sets up parity, baud, flow control 		issues, etc.... It effect both control flags and input flags.	-------------------------------------------------------------------- */	epcaparam(tty,ch);	ch->asyncflags |= ASYNC_INITIALIZED;	memoff(ch);	restore_flags(flags);	retval = block_til_ready(tty, filp, ch);	if (retval)	{		return retval;	}	/* -------------------------------------------------------------		Set this again in case a hangup set it to zero while this 		open() was waiting for the line...	--------------------------------------------------------------- */	ch->tty = tty;	save_flags(flags);	cli();	globalwinon(ch);	/* Enable Digi Data events */	bc->idata = 1;	memoff(ch);	restore_flags(flags);	return 0;} /* End pc_open */#ifdef MODULEstatic int __init epca_module_init(void){ /* Begin init_module */	unsigned long	flags;	save_flags(flags);	cli();	pc_init();	restore_flags(flags);	return(0);}module_init(epca_module_init);#endif#ifdef ENABLE_PCIstatic struct pci_driver epca_driver;#endif#ifdef MODULE/* -------------------- Begin cleanup_module  ---------------------- */static void __exit epca_module_exit(void){	int               count, crd;	struct board_info *bd;	struct channel    *ch;	unsigned long     flags;	del_timer_sync(&epca_timer);	save_flags(flags);	cli();	if ((tty_unregister_driver(pc_driver)) ||  	    (tty_unregister_driver(pc_info)))	{		printk(KERN_WARNING "<Error> - DIGI : cleanup_module failed to un-register tty driver\n");		restore_flags(flags);		return;	}	put_tty_driver(pc_driver);	put_tty_driver(pc_info);	for (crd = 0; crd < num_cards; crd++) 	{ /* Begin for each card */		bd = &boards[crd];		if (!bd)		{ /* Begin sanity check */			printk(KERN_ERR "<Error> - Digi : cleanup_module failed\n");			return;		} /* End sanity check */		ch = card_ptr[crd]; 		for (count = 0; count < bd->numports; count++, ch++) 		{ /* Begin for each port */			if (ch) 			{				if (ch->tty)					tty_hangup(ch->tty);				kfree(ch->tmp_buf);			}		} /* End for each port */	} /* End for each card */#ifdef ENABLE_PCI	pci_unregister_driver (&epca_driver);#endif	restore_flags(flags);}module_exit(epca_module_exit);#endif /* MODULE */static struct tty_operations pc_ops = {	.open = pc_open,	.close = pc_close,	.write = pc_write,	.write_room = pc_write_room,	.flush_buffer = pc_flush_buffer,	.chars_in_buffer = pc_chars_in_buffer,	.flush_chars = pc_flush_chars,	.put_char = pc_put_char,	.ioctl = pc_ioctl,	.set_termios = pc_set_termios,	.stop = pc_stop,	.start = pc_start,	.throttle = pc_throttle,	.unthrottle = pc_unthrottle,	.hangup = pc_hangup,};static int info_open(struct tty_struct *tty, struct file * filp){	return 0;}static struct tty_operations info_ops = {	.open = info_open,	.ioctl = info_ioctl,};/* ------------------ Begin pc_init  ---------------------- */int __init pc_init(void){ /* Begin pc_init */	/* ----------------------------------------------------------------		pc_init is called by the operating system during boot up prior to		any open calls being made.  In the older versions of Linux (Prior		to 2.0.0) an entry is made into tty_io.c.  A pointer to the last		memory location (from kernel space) used (kmem_start) is passed		to pc_init.  It is pc_inits responsibility to modify this value 		for any memory that the Digi driver might need and then return		this value to the operating system.  For example if the driver		wishes to allocate 1K of kernel memory, pc_init would return 		(kmem_start + 1024).  This memory (Between kmem_start and kmem_start		+ 1024) would then be available for use exclusively by the driver.  		In this case our driver does not allocate any of this kernel 		memory.	------------------------------------------------------------------*/	ulong flags;	int crd;	struct board_info *bd;	unsigned char board_id = 0;#ifdef ENABLE_PCI	int pci_boards_found, pci_count;	pci_count = 0;#endif /* ENABLE_PCI */	pc_driver = alloc_tty_driver(MAX_ALLOC);	if (!pc_driver)		return -ENOMEM;	pc_info = alloc_tty_driver(MAX_ALLOC);	if (!pc_info) {		put_tty_driver(pc_driver);		return -ENOMEM;	}	/* -----------------------------------------------------------------------		If epca_setup has not been ran by LILO set num_cards to defaults; copy		board structure defined by digiConfig into drivers board structure.		Note : If LILO has ran epca_setup then epca_setup will handle defining		num_cards as well as copying the data into the board structure.	-------------------------------------------------------------------------- */	if (!liloconfig)	{ /* Begin driver has been configured via. epcaconfig */		nbdevs = NBDEVS;		num_cards = NUMCARDS;		memcpy((void *)&boards, (void *)&static_boards,		       (sizeof(struct board_info) * NUMCARDS));	} /* End driver has been configured via. epcaconfig */	/* -----------------------------------------------------------------		Note : If lilo was used to configure the driver and the 		ignore epcaconfig option was choosen (digiepca=2) then 		nbdevs and num_cards will equal 0 at this point.  This is		okay; PCI cards will still be picked up if detected.	--------------------------------------------------------------------- */	/*  -----------------------------------------------------------		Set up interrupt, we will worry about memory allocation in		post_fep_init. 	--------------------------------------------------------------- */	printk(KERN_INFO "DIGI epca driver version %s loaded.\n",VERSION);#ifdef ENABLE_PCI	/* ------------------------------------------------------------------		NOTE : This code assumes that the number of ports found in 		       the boards array is correct.  This could be wrong if		       the card in question is PCI (And therefore has no ports 		       entry in the boards structure.)  The rest of the 		       information will be valid for PCI because the beginning		       of pc_init scans for PCI and determines i/o and base		       memory addresses.  I am not sure if it is possible to 		       read the number of ports supported by the card prior to		       it being booted (Since that is the state it is in when 		       pc_init is run).  Because it is not possible to query the		       number of supported ports until after the card has booted;		       we are required to calculate the card_ptrs as the card is	 		       is initialized (Inside post_fep_init).  The negative thing		       about this approach is that digiDload's call to GET_INFO		       will have a bad port value.  (Since this is called prior		       to post_fep_init.)	--------------------------------------------------------------------- */  	pci_boards_found = 0;	if(num_cards < MAXBOARDS)		pci_boards_found += init_PCI();	num_cards += pci_boards_found;#endif /* ENABLE_PCI */	pc_driver->owner = THIS_MODULE;	pc_driver->name = "ttyD"; 	pc_driver->devfs_name = "tts/D";	pc_driver->major = DIGI_MAJOR; 	pc_driver->minor_start = 0;	pc_driver->type = TTY_DRIVER_TYPE_SERIAL;	pc_driver->subtype = SERIAL_TYPE_NORMAL;	pc_driver->init_termios = tty_std_termios;	pc_driver->init_termios.c_iflag = 0;	pc_driver->init_termios.c_oflag = 0;	pc_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | CLOCAL | HUPCL;	pc_driver->init_termios.c_lflag = 0;	pc_driver->flags = TTY_DRIVER_REAL_RAW;	tty_set_operations(pc_driver, &pc_ops);	pc_info->owner = THIS_MODULE;	pc_info->name = "digi_ctl";	pc_info->major = DIGIINFOMAJOR;	pc_info->minor_start = 0;	pc_info->type = TTY_DRIVER_TYPE_SERIAL;	pc_info->subtype = SERIAL_TYPE_INFO;	pc_info->init_termios = tty_std_termios;	pc_info->init_termios.c_iflag = 0;	pc_info->init_termios.c_oflag = 0;	pc_info->init_termios.c_lflag = 0;	pc_info->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL;	pc_info->flags = TTY_DRIVER_REAL_RAW;	tty_set_operations(pc_info, &info_ops);	save_flags(flags);	cli();	for (crd = 0; crd < num_cards; crd++) 	{ /* Begin for each card */		/*  ------------------------------------------------------------------			This is where the appropriate memory handlers for the hardware is			set.  Everything at runtime blindly jumps through these vectors.		---------------------------------------------------------------------- */		/* defined in epcaconfig.h */		bd = &boards[crd];		switch (bd->type)		{ /* Begin switch on bd->type {board type} */			case PCXEM:			case EISAXEM:				bd->memwinon     = pcxem_memwinon ;				bd->memwinoff    = pcxem_memwinoff ;				bd->globalwinon  = pcxem_globalwinon ;				bd->txwinon      = pcxem_txwinon ;				bd->rxwinon      = pcxem_rxwinon ;				bd->memoff       = pcxem_memoff ;				bd->assertgwinon = dummy_assertgwinon;				bd->assertmemoff = dummy_assertmemoff;				break;			case PCIXEM:			case PCIXRJ:			case PCIXR:				bd->memwinon     = dummy_memwinon;				bd->memwinoff    = dummy_memwinoff;				bd->globalwinon  = dummy_globalwinon;				bd->txwinon      = dummy_txwinon;				bd->rxwinon      = dummy_rxwinon;				bd->memoff       = dummy_memoff;				bd->assertgwinon = dummy_assertgwinon;				bd->assertmemoff = dummy_assertmemoff;				break;			case PCXE:			case PCXEVE:				bd->memwinon     = pcxe_memwinon;				bd->memwinoff    = pcxe_memwinoff;				bd->globalwinon  = pcxe_globalwinon;				bd->txwinon      = pcxe_txwinon;				bd->rxwinon      = pcxe_rxwinon;				bd->memoff       = pcxe_memoff;				bd->assertgwinon = dummy_assertgwinon;				bd->assertmemoff = dummy_assertmemoff;				break;			case PCXI:			case PC64XE:				bd->memwinon     = pcxi_memwinon;				bd->memwinoff    = pcxi_memwinoff;				bd->globalwinon  = pcxi_globalwinon;				bd->txwinon      = pcxi_txwinon;				bd->rxwinon      = pcxi_rxwinon;				bd->memoff       = pcxi_memoff;				bd->assertgwinon = pcxi_assertgwinon;				bd->assertmemoff = pcxi_assertmemoff;				break;			default:				break;		} /* End switch on bd->type */		/* ---------------------------------------------------------------			Some cards need a memory segment to be defined for use in 			transmit and receive windowing operations.  These boards			are listed in the below switch.  In the case of the XI the			amount of memory on the board is variable so the memory_seg			is also variable.  This code determines what they segment 			should be.		----------------------------------------------------------------- */		switch (bd->type)		{ /* Begin switch on bd->type {board type} */			case PCXE:			case PCXEVE:

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?