pcxx.c

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

C
2,385
字号
		do		{			tail = bc->tout;		} while (tail != bc->tout);				tail &= (size - 1);		stlen = (head >= tail) ? (size - (head - tail) - 1) : (tail - head - 1);		count = min(stlen, count);		memoff(ch);		restore_flags(flags);		if (count)			if (copy_from_user(ch->tmp_buf, buf, count))				count = 0;		buf = ch->tmp_buf;	}	/*	 * All data is now local	 */	total = 0;	save_flags(flags);	cli();	globalwinon(ch);	head = bc->tin & (size - 1);	tail = bc->tout;	if (tail != bc->tout)		tail = bc->tout;	tail &= (size - 1);	if (head >= tail) {		remain = size - (head - tail) - 1;		stlen = size - head;	}	else {		remain = tail - head - 1;		stlen = remain;	}	count = min(remain, count);	txwinon(ch);	while (count > 0) {		stlen = min(count, stlen);		memcpy(ch->txptr + head, buf, stlen);		buf += stlen;		count -= stlen;		total += stlen;		head += stlen;		if (head >= size) {			head = 0;			stlen = tail;		}	}	ch->statusflags |= TXBUSY;	globalwinon(ch);	bc->tin = head;	if ((ch->statusflags & LOWWAIT) == 0) {		ch->statusflags |= LOWWAIT;		bc->ilow = 1;	}	memoff(ch);	restore_flags(flags);		if(from_user)		up(&ch->tmp_buf_sem);	return(total);}static void pcxe_put_char(struct tty_struct *tty, unsigned char c){	pcxe_write(tty, 0, &c, 1);	return;}static int pcxe_write_room(struct tty_struct *tty){	struct channel *ch;	int remain;	remain = 0;	if ((ch=chan(tty))!=NULL) {		volatile struct board_chan *bc;		unsigned int head, tail;		unsigned long flags;		save_flags(flags);		cli();		globalwinon(ch);		bc = ch->brdchan;		head = bc->tin & (ch->txbufsize - 1);		tail = bc->tout;		if (tail != bc->tout)			tail = bc->tout;		tail &= (ch->txbufsize - 1);		if((remain = tail - head - 1) < 0 )			remain += ch->txbufsize;		if (remain && (ch->statusflags & LOWWAIT) == 0) {			ch->statusflags |= LOWWAIT;			bc->ilow = 1;		}		memoff(ch);		restore_flags(flags);	}	return remain;}static int pcxe_chars_in_buffer(struct tty_struct *tty){	int chars;	unsigned int ctail, head, tail;	int remain;	unsigned long flags;	struct channel *ch;	volatile struct board_chan *bc;	if ((ch=chan(tty))==NULL)		return(0);	save_flags(flags);	cli();	globalwinon(ch);	bc = ch->brdchan;	tail = bc->tout;	head = bc->tin;	ctail = ch->mailbox->cout;	if(tail == head && ch->mailbox->cin == ctail && bc->tbusy == 0)		chars = 0;	else {		head = bc->tin & (ch->txbufsize - 1);		tail &= (ch->txbufsize - 1);		if((remain = tail - head - 1) < 0 )			remain += ch->txbufsize;		chars = (int)(ch->txbufsize - remain);		/* 		 * Make it possible to wakeup anything waiting for output		 * in tty_ioctl.c, etc.		 */		if(!(ch->statusflags & EMPTYWAIT))			setup_empty_event(tty,ch);	}	memoff(ch);	restore_flags(flags);	return(chars);}static void pcxe_flush_buffer(struct tty_struct *tty){	unsigned int tail;	volatile struct board_chan *bc;	struct channel *ch;	unsigned long flags;	if ((ch=chan(tty))==NULL)		return;	save_flags(flags);	cli();	globalwinon(ch);	bc = ch->brdchan;	tail = bc->tout;	fepcmd(ch, STOUT, (unsigned) tail, 0, 0, 0);	memoff(ch);	restore_flags(flags);	tty_wakeup(tty);}static void pcxe_flush_chars(struct tty_struct *tty){	struct channel * ch;	if ((ch=chan(tty))!=NULL) {		unsigned long flags;		save_flags(flags);		cli();		if ((ch->statusflags & TXBUSY) && !(ch->statusflags & EMPTYWAIT))			setup_empty_event(tty,ch);		restore_flags(flags);	}}#ifndef MODULE/* * Driver setup function when linked into the kernel to optionally parse multible * "digi="-lines and initialize the driver at boot time. No probing. */void __init pcxx_setup(char *str, int *ints){	struct board_info board;	int               i, j, last;	char              *temp, *t2;	unsigned          len;	numcards=0;	memset(&board, 0, sizeof(board));	for(last=0,i=1;i<=ints[0];i++)		switch(i)		{			case 1:				board.status = ints[i];				last = i;				break;			case 2:				board.type = ints[i];				last = i;				break;			case 3:				board.altpin = ints[i];				last = i;				break;			case 4:				board.numports = ints[i];				last = i;				break;			case 5:				board.port = ints[i];				last = i;				break;			case 6:				board.membase = ints[i];				last = i;				break;			default:				printk("PC/Xx: Too many integer parms\n");				return;		}	while (str && *str) 	{		/* find the next comma or terminator */		temp = str;		while (*temp && (*temp != ','))			temp++;		if (!*temp)			temp = NULL;		else			*temp++ = 0;		i = last + 1;		switch(i)		{			case 1:				len = strlen(str);				if (strncmp("Disable", str, len) == 0) 					board.status = 0;				else					if (strncmp("Enable", str, len) == 0)						board.status = 1;					else					{						printk("PC/Xx: Invalid status %s\n", str);						return;					}				last = i;				break;			case 2:				for(j=0;j<PCXX_NUM_TYPES;j++)					if (strcmp(board_desc[j], str) == 0)						break;				if (i<PCXX_NUM_TYPES) 					board.type = j;				else				{					printk("PC/Xx: Invalid board name: %s\n", str);					return;				}				last = i;				break;			case 3:				len = strlen(str);				if (strncmp("Disable", str, len) == 0) 					board.altpin = 0;				else					if (strncmp("Enable", str, len) == 0)						board.altpin = 1;					else					{						printk("PC/Xx: Invalid altpin %s\n", str);						return;					}				last = i;				break;			case 4:				t2 = str;				while (isdigit(*t2))					t2++;				if (*t2)				{					printk("PC/Xx: Invalid port count %s\n", str);					return;				}				board.numports = simple_strtoul(str, NULL, 0);				last = i;				break;			case 5:				t2 = str;				while (isxdigit(*t2))					t2++;				if (*t2)				{					printk("PC/Xx: Invalid io port address %s\n", str);					return;				}				board.port = simple_strtoul(str, NULL, 16);				last = i;				break;			case 6:				t2 = str;				while (isxdigit(*t2))					t2++;				if (*t2)				{					printk("PC/Xx: Invalid memory base %s\n", str);					return;				}				board.membase = simple_strtoul(str, NULL, 16);				last = i;				break;			default:				printk("PC/Xx: Too many string parms\n");				return;		}		str = temp;	}	if (last < 6)  	{		printk("PC/Xx: Insufficient parms specified\n");		return;	}         /* I should REALLY validate the stuff here */	memcpy(&boards[numcards],&board, sizeof(board));	printk("PC/Xx: Added board %i, %s %s %i ports at 0x%4.4X base 0x%6.6X\n", 		numcards, board_desc[board.type], board_mem[board.type], 		board.numports, board.port, (unsigned int) board.membase);	/* keep track of my initial minor number */        if (numcards)		boards[numcards].first_minor = boards[numcards-1].first_minor + boards[numcards-1].numports;	else		boards[numcards].first_minor = 0;	/* yeha!  string parameter was successful! */	numcards++;}#endifstatic struct tty_operations pcxe_ops = {	.open = pcxe_open,	.close = pcxe_close,	.write = pcxe_write,	.put_char = pcxe_put_char,	.flush_chars = pcxe_flush_chars,	.write_room = pcxe_write_room,	.chars_in_buffer = pcxe_chars_in_buffer,	.flush_buffer = pcxe_flush_buffer,	.ioctl = pcxe_ioctl,	.throttle = pcxe_throttle,	.unthrottle = pcxe_unthrottle,	.set_termios = pcxe_set_termios,	.stop = pcxe_stop,	.start = pcxe_start,	.hangup = pcxe_hangup,	.tiocmget = pcxe_tiocmget,	.tiocmset = pcxe_tiocmset,};/* * function to initialize the driver with the given parameters, which are either * the default values from this file or the parameters given at boot. */static int __init pcxe_init(void){	ulong memory_seg=0, memory_size=0;	int lowwater, enabled_cards=0, i, crd, shrinkmem=0, topwin = 0xff00L, botwin=0x100L;	int ret = -ENOMEM;	unchar *fepos, *memaddr, *bios, v;	volatile struct global_data *gd;	volatile struct board_chan *bc;	struct board_info *bd;	struct channel *ch;	printk(KERN_NOTICE "Digiboard PC/X{i,e,eve} driver v%s\n", VERSION);#ifdef MODULE	for (i = 0; i < MAX_DIGI_BOARDS; i++) {		if (io[i]) {			numcards = 0;			break;		}	}	if (numcards == 0) {		int first_minor = 0;		for (i = 0; i < MAX_DIGI_BOARDS; i++) {			if (io[i] == 0) {				boards[i].port    = 0;				boards[i].status  = DISABLED;			}			else {				boards[i].port         = (ushort)io[i];				boards[i].status       = ENABLED;				boards[i].first_minor  = first_minor;				numcards=i+1;			}			if (membase[i])				boards[i].membase = (ulong)membase[i];			else				boards[i].membase = 0xD0000;			if (memsize[i])				boards[i].memsize = (ulong)(memsize[i] * 1024);			else				boards[i].memsize = 0;			if (altpin[i])				boards[i].altpin  = ON;			else				boards[i].altpin  = OFF;			if (numports[i])				boards[i].numports  = (ushort)numports[i];			else				boards[i].numports  = 16;			boards[i].region = NULL;			first_minor += boards[i].numports;		}	}#endif	if (numcards <= 0)	{		printk("PC/Xx: No cards configured, driver not active.\n");		return -EIO;	}#if 1	if (debug)	    for (i = 0; i < numcards; i++) {		    printk("Card %d:status=%d, port=0x%x, membase=0x%lx, memsize=0x%lx, altpin=%d, numports=%d, first_minor=%d\n",			    i+1,			    boards[i].status,			    boards[i].port,			    boards[i].membase,			    boards[i].memsize,			    boards[i].altpin,			    boards[i].numports,			    boards[i].first_minor);	    }#endif	for (i=0;i<numcards;i++)		nbdevs += boards[i].numports;	if (nbdevs <= 0)	{		printk("PC/Xx: No devices activated, driver not active.\n");		return -EIO;	}	pcxe_driver = alloc_tty_driver(nbdevs);	if (!pcxe_driver)		return -ENOMEM;	/*	 * this turns out to be more memory efficient, as there are no 	 * unused spaces.	 */	digi_channels = kmalloc(sizeof(struct channel) * nbdevs, GFP_KERNEL);	if (!digi_channels) {		printk(KERN_ERR "Unable to allocate digi_channel struct\n");		put_tty_driver(pcxe_driver);		return -ENOMEM;	}	memset(digi_channels, 0, sizeof(struct channel) * nbdevs);	init_timer(&pcxx_timer);	pcxx_timer.function = pcxxpoll;	pcxe_driver->owner = THIS_MODULE;	pcxe_driver->name = "ttyD";	pcxe_driver->devfs_name = "pcxe/";	pcxe_driver->major = DIGI_MAJOR; 	pcxe_driver->minor_start = 0;	pcxe_driver->type = TTY_DRIVER_TYPE_SERIAL;	pcxe_driver->subtype = SERIAL_TYPE_NORMAL;	pcxe_driver->init_termios = tty_std_termios;	pcxe_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL;	pcxe_driver->flags = TTY_DRIVER_REAL_RAW;	tty_set_operations(pcxe_driver, &pcxe_ops);	for(crd=0; crd < numcards; crd++) {		bd = &boards[crd];		outb(FEPRST, bd->port);		mdelay(1);		for(i=0; (inb(bd->port) & FEPMASK) != FEPRST; i++) {			if(i > 100) {				printk("PC/Xx: Board not found at port 0x%x! Check switch settings.\n",					bd->port);				bd->status = DISABLED;				break;			}#ifdef MODULE			schedule();#endif			mdelay(10);		}		if(bd->status == DISABLED)			continue;		v = inb(bd->port);		if((v & 0x1) == 0x1) {			if((v & 0x30) == 0) {        /* PC/Xi 64K card */				memory_seg = 0xf000;				memory_size = 0x10000;			} 			if((v & 0x30) == 0x10) {     /* PC/Xi 128K card */				memory_seg = 0xe000;				memory_size = 0x20000;			}						if((v & 0x30) == 0x20) {     /* PC/Xi 256K card */				memory_seg = 0xc000;				memory_size = 0x40000;			}			if((v & 0x30) == 0x30) {     /* PC/Xi 512K card */				memory_seg = 0x8000;				memory_size = 0x80000;			}			bd->type = PCXI;		} else {			if((v & 0x1) == 0x1) {				bd->status = DISABLED;   /* PC/Xm unsupported card */				printk("PC/Xx: PC/Xm at 0x%x not supported!!\n", bd->port);				continue;			} else {				if(v & 0xC0) {    					topwin = 0x1f00L;					outb((((ulong)bd->membase>>8) & 0xe0) | 0x10, bd->port+2);					outb(((ulong)bd->membase>>16) & 0xff, bd->port+3);					bd->type = PCXEVE; /* PC/Xe 8K card */				} else { 					bd->type = PCXE;    /* PC/Xe 64K card */				}									memory_seg = 0xf000;				memory_size = 0x10000;			}

⌨️ 快捷键说明

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