epca.c

来自「linux 内核源代码」· C语言 代码 · 共 2,328 行 · 第 1/5 页

C
2,328
字号
	 * 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.	 */	globalwinon(ch);	ch->statusflags = 0;	/* Save boards current modem status */	ch->imodem = readb(&bc->mstat);	/*	 * Set receive head and tail ptrs to each other. This indicates no data	 * available to read.	 */	head = readw(&bc->rin);	writew(head, &bc->rout);	/* 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);	spin_unlock_irqrestore(&epca_lock, 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...	 */	spin_lock_irqsave(&epca_lock, flags);	ch->tty = tty;	globalwinon(ch);	/* Enable Digi Data events */	writeb(1, &bc->idata);	memoff(ch);	spin_unlock_irqrestore(&epca_lock, flags);	return 0;}static int __init epca_module_init(void){	return pc_init();}module_init(epca_module_init);static struct pci_driver epca_driver;static void __exit epca_module_exit(void){	int               count, crd;	struct board_info *bd;	struct channel    *ch;	del_timer_sync(&epca_timer);	if (tty_unregister_driver(pc_driver) || tty_unregister_driver(pc_info))	{		printk(KERN_WARNING "epca: cleanup_module failed to un-register tty driver\n");		return;	}	put_tty_driver(pc_driver);	put_tty_driver(pc_info);	for (crd = 0; crd < num_cards; crd++) {		bd = &boards[crd];		if (!bd) { /* sanity check */			printk(KERN_ERR "<Error> - Digi : cleanup_module failed\n");			return;		}		ch = card_ptr[crd];		for (count = 0; count < bd->numports; count++, ch++) {			if (ch && ch->tty)				tty_hangup(ch->tty);		}	}	pci_unregister_driver(&epca_driver);}module_exit(epca_module_exit);static const 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,};static int __init pc_init(void){	int crd;	struct board_info *bd;	unsigned char board_id = 0;	int err = -ENOMEM;	int pci_boards_found, pci_count;	pci_count = 0;	pc_driver = alloc_tty_driver(MAX_ALLOC);	if (!pc_driver)		goto out1;	pc_info = alloc_tty_driver(MAX_ALLOC);	if (!pc_info)		goto out2;	/*	 * 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) {		/* driver has been configured via. epcaconfig */		nbdevs = NBDEVS;		num_cards = NUMCARDS;		memcpy(&boards, &static_boards,		       sizeof(struct board_info) * NUMCARDS);	}	/*	 * 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);	/*	 * 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 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;	pc_driver->owner = THIS_MODULE;	pc_driver->name = "ttyD";	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->init_termios.c_ispeed = 9600;	pc_driver->init_termios.c_ospeed = 9600;	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->init_termios.c_ispeed = 9600;	pc_info->init_termios.c_ospeed = 9600;	pc_info->flags = TTY_DRIVER_REAL_RAW;	tty_set_operations(pc_info, &info_ops);	for (crd = 0; crd < num_cards; crd++) {		/*		 * 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) {		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;		}		/*		 * 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) {		case PCXE:		case PCXEVE:		case PC64XE:			bd->memory_seg = 0xf000;			break;		case PCXI:			board_id = inb((int)bd->port);			if ((board_id & 0x1) == 0x1) {				/* it's an XI card */				/* Is it a 64K board */				if ((board_id & 0x30) == 0)					bd->memory_seg = 0xf000;				/* Is it a 128K board */				if ((board_id & 0x30) == 0x10)					bd->memory_seg = 0xe000;				/* Is is a 256K board */				if ((board_id & 0x30) == 0x20)					bd->memory_seg = 0xc000;				/* Is it a 512K board */				if ((board_id & 0x30) == 0x30)					bd->memory_seg = 0x8000;			} else				printk(KERN_ERR "epca: Board at 0x%x doesn't appear to be an XI\n",(int)bd->port);			break;		}	}	err = tty_register_driver(pc_driver);	if (err) {		printk(KERN_ERR "Couldn't register Digi PC/ driver");		goto out3;	}	err = tty_register_driver(pc_info);	if (err) {		printk(KERN_ERR "Couldn't register Digi PC/ info ");		goto out4;	}	/* Start up the poller to check for events on all enabled boards */	init_timer(&epca_timer);	epca_timer.function = epcapoll;	mod_timer(&epca_timer, jiffies + HZ/25);	return 0;out4:	tty_unregister_driver(pc_driver);out3:	put_tty_driver(pc_info);out2:	put_tty_driver(pc_driver);out1:	return err;}static void post_fep_init(unsigned int crd){	int i;	void __iomem *memaddr;	struct global_data __iomem *gd;	struct board_info *bd;	struct board_chan __iomem *bc;	struct channel *ch;	int shrinkmem = 0, lowwater;	/*	 * This call is made by the user via. the ioctl call DIGI_INIT. It is	 * responsible for setting up all the card specific stuff.	 */	bd = &boards[crd];	/*	 * If this is a PCI board, get the port info. Remember PCI cards do not	 * have entries into the epcaconfig.h file, so we can't get the number	 * of ports from it. Unfortunetly, this means that anyone doing a	 * DIGI_GETINFO before the board has booted will get an invalid number	 * of ports returned (It should return 0). Calls to DIGI_GETINFO after	 * DIGI_INIT has been called will return the proper values.	 */	if (bd->type >= PCIXEM) { /* Begin get PCI number of ports */		/*		 * Below we use XEMPORTS as a memory offset regardless of which		 * PCI card it is. This is because all of the supported PCI		 * cards have the same memory offset for the channel data. This		 * will have to be changed if we ever develop a PCI/XE card.		 * NOTE : The FEP manual states that the port offset is 0xC22		 * as opposed to 0xC02. This is only true for PC/XE, and PC/XI		 * cards; not for the XEM, or CX series. On the PCI cards the		 * number of ports is determined by reading a ID PROM located		 * in the box attached to the card. The card can then determine		 * the index the id to determine the number of ports available.		 * (FYI - The id should be located at 0x1ac (And may use up to		 * 4 bytes if the box in question is a XEM or CX)).		 */		/* PCI cards are already remapped at this point ISA are not */		bd->numports = readw(bd->re_map_membase + XEMPORTS);		epcaassert(bd->numports <= 64,"PCI returned a invalid number of ports");		nbdevs += (bd->numports);	} else {		/* Fix up the mappings for ISA/EISA etc */		/* FIXME: 64K - can we be smarter ? */		bd->re_map_membase = ioremap(bd->membase, 0x10000);	}	if (crd != 0)		card_ptr[crd] = card_ptr[crd-1] + boards[crd-1].numports;	else		card_ptr[crd] = &digi_channels[crd]; /* <- For card 0 only */	ch = card_ptr[crd];	epcaassert(ch <= &digi_channels[nbdevs - 1], "ch out of range");	memaddr = bd->re_map_membase;	/*	 * The below assignment will set bc to point at the BEGINING of the	 * cards channel structures. For 1 card there will be between 8 and 64	 * of these structures.	 */	bc = memaddr + CHANSTRUCT;	/*	 * The below assignment will set gd to point at the BEGINING of global	 * memory address 0xc00. The first data in that global memory actually	 * starts at address 0xc1a. The command in pointer begins at 0xd10.	 */	gd = memaddr + GLOBAL;	/*	 * XEPORTS (address 0xc22) points at the number of channels the card	 * supports. (For 64XE, XI, XEM, and XR use 0xc02)	 */	if ((bd->type == PCXEVE || bd->type == PCXE) && (readw(memaddr + XEPORTS) < 3))		shrinkmem = 1;	if (bd->type < PCIXEM)		if (!request_region((int)bd->port, 4, board_desc[bd->type]))			return;	memwinon(bd, 0);	/*	 * Remember ch is the main drivers channels structure, while bc is the	 * cards channel structure.	 */	for (i = 0; i < bd->numports; i++, ch++, bc++) {		unsigned long flags;		u16 tseg, rseg;		ch->brdchan = bc;		ch->mailbox = gd;		INIT_WORK(&ch->tqueue, do_softint);		ch->board = &boards[crd];		spin_lock_irqsave(&epca_lock, flags);		switch (bd->type) {		/*		 * Since some of the boards use different bitmaps for		 * their control signals we cannot hard code these		 * values and retain portability. We virtualize this		 * data here.		 */		case EISAXEM:		case PCXEM:		case PCIXEM:		case PCIXRJ:		case PCIXR:			ch->m_rts = 0x02;

⌨️ 快捷键说明

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