epca.c

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

C
2,180
字号
			case PC64XE:				bd->memory_seg = 0xf000;			break;			case PCXI:				board_id = inb((int)bd->port);				if ((board_id & 0x1) == 0x1) 				{ /* Begin 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;				} /* End it is an XI card */				else				{					printk(KERN_ERR "<Error> - Board at 0x%x doesn't appear to be an XI\n",(int)bd->port);				}			break;		} /* End switch on bd->type */	} /* End for each card */	if (tty_register_driver(pc_driver))		panic("Couldn't register Digi PC/ driver");	if (tty_register_driver(pc_info))		panic("Couldn't register Digi PC/ info ");	/* -------------------------------------------------------------------	   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);	restore_flags(flags);	return 0;} /* End pc_init *//* ------------------ Begin post_fep_init  ---------------------- */static void post_fep_init(unsigned int crd){ /* Begin post_fep_init */	int i;	unchar *memaddr;	volatile struct global_data *gd;	struct board_info *bd;	volatile struct board_chan *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) /* If the board in question is PCI */	{ /* 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)).  		------------------------------------------------------------------------ */ 		bd->numports = (unsigned short)*(unsigned char *)bus_to_virt((unsigned long)                                                       (bd->re_map_membase + XEMPORTS));				epcaassert(bd->numports <= 64,"PCI returned a invalid number of ports");		nbdevs += (bd->numports);	} /* End get PCI number of ports */	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 = (unchar *)bd->re_map_membase;	/* 	   The below command is necessary because newer kernels (2.1.x and	   up) do not have a 1:1 virtual to physical mapping.  The below	   call adjust for that.	*/	memaddr = (unsigned char *)bus_to_virt((unsigned long)memaddr);	/* -----------------------------------------------------------------		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 = (volatile struct board_chan *)((ulong)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 = (volatile struct global_data *)((ulong)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)) &&	    (*(ushort *)((ulong)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 every port on the card do ..... */	for (i = 0; i < bd->numports; i++, ch++, bc++) 	{ /* Begin for each port */		ch->brdchan        = bc;		ch->mailbox        = gd; 		INIT_WORK(&ch->tqueue, do_softint, ch);		ch->board          = &boards[crd];		switch (bd->type)		{ /* Begin 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 ;				ch->m_dcd = 0x80 ; 				ch->m_dsr = 0x20 ;				ch->m_cts = 0x10 ;				ch->m_ri  = 0x40 ;				ch->m_dtr = 0x01 ;				break;			case PCXE:			case PCXEVE:			case PCXI:			case PC64XE:				ch->m_rts = 0x02 ;				ch->m_dcd = 0x08 ; 				ch->m_dsr = 0x10 ;				ch->m_cts = 0x20 ;				ch->m_ri  = 0x40 ;				ch->m_dtr = 0x80 ;				break;			} /* End switch bd->type */		if (boards[crd].altpin) 		{			ch->dsr = ch->m_dcd;			ch->dcd = ch->m_dsr;			ch->digiext.digi_flags |= DIGI_ALTPIN;		}		else 		{ 			ch->dcd = ch->m_dcd;			ch->dsr = ch->m_dsr;		}			ch->boardnum   = crd;		ch->channelnum = i;		ch->magic      = EPCA_MAGIC;		ch->tty        = NULL;		if (shrinkmem) 		{			fepcmd(ch, SETBUFFER, 32, 0, 0, 0);			shrinkmem = 0;		}		switch (bd->type)		{ /* Begin switch bd->type */			case PCIXEM:			case PCIXRJ:			case PCIXR:				/* Cover all the 2MEG cards */				ch->txptr = memaddr + (((bc->tseg) << 4) & 0x1fffff);				ch->rxptr = memaddr + (((bc->rseg) << 4) & 0x1fffff);				ch->txwin = FEPWIN | ((bc->tseg) >> 11);				ch->rxwin = FEPWIN | ((bc->rseg) >> 11);				break;			case PCXEM:			case EISAXEM:				/* Cover all the 32K windowed cards */				/* Mask equal to window size - 1 */				ch->txptr = memaddr + (((bc->tseg) << 4) & 0x7fff);				ch->rxptr = memaddr + (((bc->rseg) << 4) & 0x7fff);				ch->txwin = FEPWIN | ((bc->tseg) >> 11);				ch->rxwin = FEPWIN | ((bc->rseg) >> 11);				break;			case PCXEVE:			case PCXE:				ch->txptr = memaddr + (((bc->tseg - bd->memory_seg) << 4) & 0x1fff);				ch->txwin = FEPWIN | ((bc->tseg - bd->memory_seg) >> 9);				ch->rxptr = memaddr + (((bc->rseg - bd->memory_seg) << 4) & 0x1fff);				ch->rxwin = FEPWIN | ((bc->rseg - bd->memory_seg) >>9 );				break;			case PCXI:			case PC64XE:				ch->txptr = memaddr + ((bc->tseg - bd->memory_seg) << 4);				ch->rxptr = memaddr + ((bc->rseg - bd->memory_seg) << 4);				ch->txwin = ch->rxwin = 0;				break;		} /* End switch bd->type */		ch->txbufhead = 0;		ch->txbufsize = bc->tmax + 1;			ch->rxbufhead = 0;		ch->rxbufsize = bc->rmax + 1;			lowwater = ch->txbufsize >= 2000 ? 1024 : (ch->txbufsize / 2);		/* Set transmitter low water mark */		fepcmd(ch, STXLWATER, lowwater, 0, 10, 0);		/* Set receiver low water mark */		fepcmd(ch, SRXLWATER, (ch->rxbufsize / 4), 0, 10, 0);		/* Set receiver high water mark */		fepcmd(ch, SRXHWATER, (3 * ch->rxbufsize / 4), 0, 10, 0);		bc->edelay = 100;		bc->idata = 1;			ch->startc  = bc->startc;		ch->stopc   = bc->stopc;		ch->startca = bc->startca;		ch->stopca  = bc->stopca;			ch->fepcflag = 0;		ch->fepiflag = 0;		ch->fepoflag = 0;		ch->fepstartc = 0;		ch->fepstopc = 0;		ch->fepstartca = 0;		ch->fepstopca = 0;			ch->close_delay = 50;		ch->count = 0;		ch->blocked_open = 0;		init_waitqueue_head(&ch->open_wait);		init_waitqueue_head(&ch->close_wait);		ch->tmp_buf = kmalloc(ch->txbufsize,GFP_KERNEL);		if (!(ch->tmp_buf))		{			printk(KERN_ERR "POST FEP INIT : kmalloc failed for port 0x%x\n",i);			release_region((int)bd->port, 4);			while(i-- > 0)				kfree((ch--)->tmp_buf);			return;		}		else 			memset((void *)ch->tmp_buf,0,ch->txbufsize);	} /* End for each port */	printk(KERN_INFO 	        "Digi PC/Xx Driver V%s:  %s I/O = 0x%lx Mem = 0x%lx Ports = %d\n", 	        VERSION, board_desc[bd->type], (long)bd->port, (long)bd->membase, bd->numports);	sprintf(mesg, 	        "Digi PC/Xx Driver V%s:  %s I/O = 0x%lx Mem = 0x%lx Ports = %d\n", 	        VERSION, board_desc[bd->type], (long)bd->port, (long)bd->membase, bd->numports);	console_print(mesg);	memwinoff(bd, 0);} /* End post_fep_init *//* --------------------- Begin epcapoll  ------------------------ */static void epcapoll(unsigned long ignored){ /* Begin epcapoll */	unsigned long flags;	int crd;	volatile unsigned int head, tail;	struct channel *ch;	struct board_info *bd;	/* -------------------------------------------------------------------		This routine is called upon every timer interrupt.  Even though		the Digi series cards are capable of generating interrupts this 		method of non-looping polling is more efficient.  This routine		checks for card generated events (Such as receive data, are transmit		buffer empty) and acts on those events.	----------------------------------------------------------------------- */		save_flags(flags);	cli();	for (crd = 0; crd < num_cards; crd++) 	{ /* Begin for each card */		bd = &boards[crd];		ch = card_ptr[crd];		if ((bd->status == DISABLED) || digi_poller_inhibited)			continue; /* Begin loop next interation */		/* -----------------------------------------------------------			assertmemoff is not needed here; indeed it is an empty subroutine.			It is being kept because future boards may need this as well as			some legacy boards.		---------------------------------------------------------------- */		assertmemoff(ch);		globalwinon(ch);		/* ---------------------------------------------------------------			In this case head and tail actually refer to the event queue not			the transmit or receive queue.		------------------------------------------------------------------- */		head = ch->mailbox->ein;		tail = ch->mailbox->eout;				/* If head isn't equal to tail we have an event */		if (head != tail)			doevent(crd);		memoff(ch);	} /* End for each card */	mod_timer(&epca_timer, jiffies + (HZ / 25));	restore_flags(flags);} /* End epcapoll *//* --------------------- Begin doevent  ------------------------ */static void doevent(int crd){ /* Begin doevent */	volatile unchar *eventbuf;	struct channel *ch, *chan0;	static struct tty_struct *tty;	volatile struct board_info *bd;	volatile struct board_chan *bc;	register volatile unsigned int tail, head;	register int event, channel;	register int mstat, lstat;	/* -------------------------------------------------------------------		This subroutine is called by epcapoll when an event is detected 		in the event queue.  This routine responds to those events.	--------------------------------------------------------------------- */	bd = &boards[crd];	chan0 = card_ptr[crd];	epcaassert(chan0 <= &digi_channels[nbdevs - 1], "ch out of range");	assertgwinon(chan0);	while ((tail = chan0->mailbox->eout) != (head = chan0->mailbox->ein)) 	{ /* Begin while something in event queue */		assertgwinon(chan0);		eventbuf = (volatile unchar *)bus_to_virt((ulong)(bd->re_map_membase + tail + ISTART));		/*

⌨️ 快捷键说明

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