⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 isicom.c

📁 powerpc内核mpc8241linux系统下char驱动程序
💻 C
📖 第 1 页 / 共 4 页
字号:
/* *	This program is free software; you can redistribute it and/or *	modify it under the terms of the GNU General Public License *	as published by the Free Software Foundation; either version *	2 of the License, or (at your option) any later version. * *	Original driver code supplied by Multi-Tech * *	Changes *	1/9/98	alan@redhat.com		Merge to 2.0.x kernel tree *					Obtain and use official major/minors *					Loader switched to a misc device *					(fixed range check bug as a side effect) *					Printk clean up *	9/12/98	alan@redhat.com		Rough port to 2.1.x */#include <linux/module.h>#include <linux/version.h>#include <linux/kernel.h>#include <linux/tty.h>#include <linux/termios.h>#include <linux/fs.h>#include <linux/sched.h>#include <linux/serial.h>#include <linux/mm.h>#include <linux/miscdevice.h>#include <linux/interrupt.h>#include <linux/timer.h>#include <linux/ioport.h>#include <asm/segment.h>#include <asm/uaccess.h>#include <asm/io.h>#include <asm/system.h>#include <linux/isicom.h>static int isicom_refcount = 0;static int prev_card = 3;	/*	start servicing isi_card[0]	*/static struct isi_board * irq_to_board[16] = { NULL, };static struct tty_driver isicom_normal, isicom_callout;static struct tty_struct * isicom_table[PORT_COUNT] = { NULL, };static struct termios * isicom_termios[PORT_COUNT] = { NULL, };static struct termios * isicom_termios_locked[PORT_COUNT] = { NULL, };static struct isi_board isi_card[BOARD_COUNT];static struct isi_port  isi_ports[PORT_COUNT];DECLARE_TASK_QUEUE(tq_isicom);static struct timer_list tx;static char re_schedule = 1;#ifdef ISICOM_DEBUGstatic unsigned long tx_count = 0;#endifstatic int ISILoad_open(struct inode *inode, struct file *filp);static int ISILoad_release(struct inode *inode, struct file *filp);static int ISILoad_ioctl(struct inode *inode, struct file *filp, unsigned  int cmd, unsigned long arg);static void isicom_tx(unsigned long _data);static void isicom_start(struct tty_struct * tty);static unsigned char * tmp_buf = 0;static struct semaphore tmp_buf_sem = MUTEX;/*   baud index mappings from linux defns to isi */static char linuxb_to_isib[] = {	-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 13, 15, 16, 17,     	18, 19};/*  *  Firmware loader driver specific routines * */static struct file_operations ISILoad_fops = {	NULL,	/*	lseek	*/	NULL,	/*	read	*/	NULL,	/*	write	*/	NULL,	/*	readdir	*/	NULL,	/*	select	*/	ISILoad_ioctl,	NULL,	/*	mmap	*/	ISILoad_open,	NULL,	/*	flush	*/	ISILoad_release,	NULL,	/*	fsync	*/	NULL,	/*	fasync	*/	NULL,	/*	check_media_change	*/	NULL,	/*	revalidate	*/};struct miscdevice isiloader_device = {	ISILOAD_MISC_MINOR, "isictl", &ISILoad_fops}; extern inline int WaitTillCardIsFree(unsigned short base){	unsigned long count=0;	while( (!(inw(base+0xe) & 0x1)) && (count++ < 6000000));	if (inw(base+0xe)&0x1)  		return 0;	else		return 1;}static int ISILoad_open(struct inode *inode, struct file *filp){#ifdef ISICOM_DEBUG		printk(KERN_DEBUG "ISILoad:Firmware loader Opened!!!\n");#endif		MOD_INC_USE_COUNT;	return 0;}static int ISILoad_release(struct inode *inode, struct file *filp){#ifdef ISICOM_DEBUG	printk(KERN_DEBUG "ISILoad:Firmware loader Close(Release)d\n",);#endif		MOD_DEC_USE_COUNT;	return 0;}static int ISILoad_ioctl(struct inode *inode, struct file *filp,		         unsigned int cmd, unsigned long arg){	unsigned int card, i, j, signature, status;	unsigned short word_count, base;	bin_frame frame;	/* exec_record exec_rec; */		if(get_user(card, (int *)arg))		return -EFAULT;			if(card < 0 || card >= BOARD_COUNT)		return -ENXIO;			base=isi_card[card].base;		if(base==0)		return -ENXIO;	/* disabled or not used */		switch(cmd) {		case MIOCTL_RESET_CARD:			if (!capable(CAP_SYS_ADMIN))				return -EPERM;			printk(KERN_DEBUG "ISILoad:Resetting Card%d at 0x%x ",card+1,base);											inw(base+0x8);						for(i=jiffies+HZ/100;time_before(jiffies, i););							outw(0,base+0x8); /* Reset */						for(j=1;j<=3;j++) {				for(i=jiffies+HZ;time_before(jiffies, i););				printk(".");			}				signature=(inw(base+0x4)) & 0xff;								if (!(inw(base+0xe) & 0x1) || (inw(base+0x2))) {#ifdef ISICOM_DEBUG								printk("\nbase+0x2=0x%x , base+0xe=0x%x",inw(base+0x2),inw(base+0xe));#endif								printk("\nISILoad:Card%d reset failure (Possible bad I/O Port Address 0x%x).\n",card+1,base);				return -EIO;								}							switch(signature) {			case	0xa5:			case	0xbb:			case	0xdd:	isi_card[card].port_count = 8;				     	isi_card[card].shift_count = 12;				     	break;				        			case	0xcc:	isi_card[card].port_count = 16;					isi_card[card].shift_count = 11;					break;  											default: printk("ISILoad:Card%d reset failure (Possible bad I/O Port Address 0x%x).\n",card+1,base);#ifdef ISICOM_DEBUG							 printk("Sig=0x%x\n",signature);#endif				 				 return -EIO;			}			printk("-Done\n");			return put_user(signature,(unsigned int*)arg);							case	MIOCTL_LOAD_FIRMWARE:			if (!capable(CAP_SYS_ADMIN))				return -EPERM;							if(copy_from_user(&frame, (void *) arg, sizeof(bin_frame)))				return -EFAULT;						if (WaitTillCardIsFree(base))				return -EIO;						outw(0xf0,base);	/* start upload sequence */ 			outw(0x00,base);			outw((frame.addr), base);/*      lsb of adderess    */						word_count=(frame.count >> 1) + frame.count % 2;			outw(word_count, base);			InterruptTheCard(base);						for(i=0;i<=0x2f;i++);	/* a wee bit of delay */						if (WaitTillCardIsFree(base)) 				return -EIO;							if ((status=inw(base+0x4))!=0) {				printk(KERN_WARNING "ISILoad:Card%d rejected load header:\nAddress:0x%x \nCount:0x%x \nStatus:0x%x \n", 				card+1, frame.addr, frame.count, status);				return -EIO;			}			outsw(base, (void *) frame.bin_data, word_count);						InterruptTheCard(base);						for(i=0;i<=0x0f;i++);	/* another wee bit of delay */ 						if (WaitTillCardIsFree(base)) 				return -EIO;							if ((status=inw(base+0x4))!=0) {				printk(KERN_ERR "ISILoad:Card%d got out of sync.Card Status:0x%x\n",card+1, status);				return -EIO;			}				return 0;							case	MIOCTL_READ_FIRMWARE:			if (!capable(CAP_SYS_ADMIN))				return -EPERM;							if(copy_from_user(&frame, (void *) arg, sizeof(bin_header)))				return -EFAULT;						if (WaitTillCardIsFree(base))				return -EIO;						outw(0xf1,base);	/* start download sequence */ 			outw(0x00,base);			outw((frame.addr), base);/*      lsb of adderess    */						word_count=(frame.count >> 1) + frame.count % 2;			outw(word_count+1, base);			InterruptTheCard(base);						for(i=0;i<=0xf;i++);	/* a wee bit of delay */						if (WaitTillCardIsFree(base)) 				return -EIO;							if ((status=inw(base+0x4))!=0) {				printk(KERN_WARNING "ISILoad:Card%d rejected verify header:\nAddress:0x%x \nCount:0x%x \nStatus:0x%x \n", 				card+1, frame.addr, frame.count, status);				return -EIO;			}						inw(base);			insw(base, frame.bin_data, word_count);			InterruptTheCard(base);						for(i=0;i<=0x0f;i++);	/* another wee bit of delay */ 						if (WaitTillCardIsFree(base)) 				return -EIO;							if ((status=inw(base+0x4))!=0) {				printk(KERN_ERR "ISILoad:Card%d verify got out of sync.Card Status:0x%x\n",card+1, status);				return -EIO;			}							if(copy_to_user((void *) arg, &frame, sizeof(bin_frame)))				return -EFAULT;			return 0;		case	MIOCTL_XFER_CTRL:			if (!capable(CAP_SYS_ADMIN))				return -EPERM;			if (WaitTillCardIsFree(base)) 				return -EIO;								outw(0xf2, base);			outw(0x800, base);			outw(0x0, base);			outw(0x0, base);			InterruptTheCard(base);						isi_card[card].status |= FIRMWARE_LOADED;			return 0;					default:#ifdef ISICOM_DEBUG			printk(KERN_DEBUG "ISILoad: Received Ioctl cmd 0x%x.\n", cmd); #endif		return -ENOIOCTLCMD;		}	}		        	/* *	ISICOM Driver specific routines ... * */ static inline int isicom_paranoia_check(struct isi_port const * port, kdev_t dev, 					const char * routine){#ifdef ISICOM_DEBUG 	static const char * badmagic = 			KERN_WARNING "ISICOM: Warning: bad isicom magic for dev %s in %s.\n";	static const char * badport = 			KERN_WARNING "ISICOM: Warning: NULL isicom port for dev %s in %s.\n";			if (!port) {		printk(badport, kdevname(dev), routine);		return 1;	}	if (port->magic != ISICOM_MAGIC) {		printk(badmagic, kdevname(dev), routine);		return 1;	}	#endif		return 0;}			extern inline void schedule_bh(struct isi_port * port){	queue_task(&port->bh_tqueue, &tq_isicom);	mark_bh(ISICOM_BH);} /*	Transmitter	*/static void isicom_tx(unsigned long _data){	short count = (BOARD_COUNT-1), card, base;	short txcount, wait, wrd, residue, word_count, cnt;	struct isi_port * port;	struct tty_struct * tty;	unsigned long flags;	#ifdef ISICOM_DEBUG	++tx_count;#endif			/*	find next active board	*/	card = (prev_card + 1) & 0x0003;	while(count-- > 0) {		if (isi_card[card].status & BOARD_ACTIVE) 			break;		card = (card + 1) & 0x0003;		}	if (!(isi_card[card].status & BOARD_ACTIVE))		goto sched_again;			prev_card = card;		count = isi_card[card].port_count;	port = isi_card[card].ports;	base = isi_card[card].base;	for (;count > 0;count--, port++) {		/* port not active or tx disabled to force flow control */		if (!(port->status & ISI_TXOK))			continue;				tty = port->tty;		save_flags(flags); cli();		txcount = MIN(TX_SIZE, port->xmit_cnt);		if ((txcount <= 0) || tty->stopped || tty->hw_stopped) {			restore_flags(flags);			continue;		}		wait = 200;			while(((inw(base+0x0e) & 0x01) == 0) && (wait-- > 0));		if (wait <= 0) {			restore_flags(flags);#ifdef ISICOM_DEBUG			printk(KERN_DEBUG "ISICOM: isicom_tx:Card(0x%x) found busy.\n",				card);#endif			continue;		}		if (!(inw(base + 0x02) & (1 << port->channel))) {			restore_flags(flags);#ifdef ISICOM_DEBUG								printk(KERN_DEBUG "ISICOM: isicom_tx: cannot tx to 0x%x:%d.\n",					base, port->channel + 1);#endif								continue;				}#ifdef ISICOM_DEBUG		printk(KERN_DEBUG "ISICOM: txing %d bytes, port%d.\n", 				txcount, port->channel+1); #endif			outw((port->channel << isi_card[card].shift_count) | txcount					, base);		residue = NO;		wrd = 0;					while (1) {			cnt = MIN(txcount, (SERIAL_XMIT_SIZE - port->xmit_tail));			if (residue == YES) {				residue = NO;				if (cnt > 0) {					wrd |= (port->xmit_buf[port->xmit_tail] << 8);					port->xmit_tail = (port->xmit_tail + 1) & (SERIAL_XMIT_SIZE - 1);					port->xmit_cnt--;					txcount--;					cnt--;					outw(wrd, base);							}				else {					outw(wrd, base);					break;				}			}					if (cnt <= 0) break;			word_count = cnt >> 1;			outsw(base, port->xmit_buf+port->xmit_tail, word_count);			port->xmit_tail = (port->xmit_tail + (word_count << 1)) &						(SERIAL_XMIT_SIZE - 1);			txcount -= (word_count << 1);			port->xmit_cnt -= (word_count << 1);			if (cnt & 0x0001) {				residue = YES;				wrd = port->xmit_buf[port->xmit_tail];				port->xmit_tail = (port->xmit_tail + 1) & (SERIAL_XMIT_SIZE - 1);				port->xmit_cnt--;				txcount--;			}		}/* *	Replaced the code below with hopefully a faster loop - sameer *//*							while (1) {			wrd = port->xmit_buf[port->xmit_tail++];			port->xmit_tail = port->xmit_tail & (SERIAL_XMIT_SIZE - 1);			port->xmit_cnt--;			if (--txcount > 0) {				wrd |= (port->xmit_buf[port->xmit_tail++] << 8);				port->xmit_tail = port->xmit_tail & (SERIAL_XMIT_SIZE - 1);				port->xmit_cnt--;				outw(wrd, base);				if (--txcount <= 0) break;			}			else {				outw(wrd, base);				break;			}		}*/		InterruptTheCard(base);		if (port->xmit_cnt <= 0)			port->status &= ~ISI_TXOK;		if (port->xmit_cnt <= WAKEUP_CHARS)			schedule_bh(port);		restore_flags(flags);	}			/*	schedule another tx for hopefully in about 10ms	*/	sched_again:		if (!re_schedule)			return;	init_timer(&tx);	tx.expires = jiffies + HZ/100;	tx.data = 0;	tx.function = isicom_tx;	add_timer(&tx);		return;	}		 /* 	Interrupt handlers 	*/static void do_isicom_bh(void){	run_task_queue(&tq_isicom);}

⌨️ 快捷键说明

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