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

📄 isicom.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
		return;			save_flags(flags); cli();	isicom_config_port(port);	restore_flags(flags);		if ((old_termios->c_cflag & CRTSCTS) &&	    !(tty->termios->c_cflag & CRTSCTS)) {			tty->hw_stopped = 0;		isicom_start(tty);   	}    }/* throttle et all */static void isicom_throttle(struct tty_struct * tty){	struct isi_port * port = (struct isi_port *) tty->driver_data;	struct isi_board * card = port->card;	unsigned long flags;		if (isicom_paranoia_check(port, tty->device, "isicom_throttle"))		return;		/* tell the card that this port cannot handle any more data for now */	save_flags(flags); cli();	card->port_status &= ~(1 << port->channel);	outw(card->port_status, card->base + 0x02);	restore_flags(flags);}/* unthrottle et all */static void isicom_unthrottle(struct tty_struct * tty){	struct isi_port * port = (struct isi_port *) tty->driver_data;	struct isi_board * card = port->card;	unsigned long flags;		if (isicom_paranoia_check(port, tty->device, "isicom_unthrottle"))		return;		/* tell the card that this port is ready to accept more data */	save_flags(flags); cli();	card->port_status |= (1 << port->channel);	outw(card->port_status, card->base + 0x02);	restore_flags(flags);}/* stop et all */static void isicom_stop(struct tty_struct * tty){	struct isi_port * port = (struct isi_port *) tty->driver_data;	if (isicom_paranoia_check(port, tty->device, "isicom_stop"))		return;		/* this tells the transmitter not to consider this port for	   data output to the card. */	port->status &= ~ISI_TXOK;}/* start et all */static void isicom_start(struct tty_struct * tty){	struct isi_port * port = (struct isi_port *) tty->driver_data;		if (isicom_paranoia_check(port, tty->device, "isicom_start"))		return;		/* this tells the transmitter to consider this port for	   data output to the card. */	port->status |= ISI_TXOK;}/* hangup et all */static void do_isicom_hangup(void * data){	struct isi_port * port = (struct isi_port *) data;	struct tty_struct * tty;		tty = port->tty;	if (tty)		tty_hangup(tty);	/* FIXME: module removal race here - AKPM */	MOD_DEC_USE_COUNT;}static void isicom_hangup(struct tty_struct * tty){	struct isi_port * port = (struct isi_port *) tty->driver_data;		if (isicom_paranoia_check(port, tty->device, "isicom_hangup"))		return;		isicom_shutdown_port(port);	port->count = 0;	port->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE);	port->tty = 0;	wake_up_interruptible(&port->open_wait);}/* flush_buffer et all */static void isicom_flush_buffer(struct tty_struct * tty){	struct isi_port * port = (struct isi_port *) tty->driver_data;	unsigned long flags;		if (isicom_paranoia_check(port, tty->device, "isicom_flush_buffer"))		return;		save_flags(flags); cli();	port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;	restore_flags(flags);		wake_up_interruptible(&tty->write_wait);	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&	    tty->ldisc.write_wakeup)		(tty->ldisc.write_wakeup)(tty);}static int register_ioregion(void){	int count, done=0;	for (count=0; count < BOARD_COUNT; count++ ) {		if (isi_card[count].base) {			if (check_region(isi_card[count].base,16)) {				printk(KERN_DEBUG "ISICOM: I/O Region 0x%x-0x%x is busy. Card%d will be disabled.\n",					isi_card[count].base,isi_card[count].base+15,count+1);				isi_card[count].base=0;			}			else {				request_region(isi_card[count].base,16,ISICOM_NAME);#ifdef ISICOM_DEBUG								printk(KERN_DEBUG "ISICOM: I/O Region 0x%x-0x%x requested for Card%d.\n",isi_card[count].base,isi_card[count].base+15,count+1);#endif								done++;			}		}		}	return done;}static void unregister_ioregion(void){	int count;	for (count=0; count < BOARD_COUNT; count++ ) 		if (isi_card[count].base) {			release_region(isi_card[count].base,16);#ifdef ISICOM_DEBUG						printk(KERN_DEBUG "ISICOM: I/O Region 0x%x-0x%x released for Card%d.\n",isi_card[count].base,isi_card[count].base+15,count+1);#endif					}}static int register_drivers(void){	int error;	/* tty driver structure initialization */	memset(&isicom_normal, 0, sizeof(struct tty_driver));	isicom_normal.magic	= TTY_DRIVER_MAGIC;	isicom_normal.name 	= "ttyM";	isicom_normal.major	= ISICOM_NMAJOR;	isicom_normal.minor_start	= 0;	isicom_normal.num	= PORT_COUNT;	isicom_normal.type	= TTY_DRIVER_TYPE_SERIAL;	isicom_normal.subtype	= SERIAL_TYPE_NORMAL;	isicom_normal.init_termios	= tty_std_termios;	isicom_normal.init_termios.c_cflag	= 				B9600 | CS8 | CREAD | HUPCL |CLOCAL;	isicom_normal.flags	= TTY_DRIVER_REAL_RAW;	isicom_normal.refcount	= &isicom_refcount;		isicom_normal.table	= isicom_table;	isicom_normal.termios	= isicom_termios;	isicom_normal.termios_locked	= isicom_termios_locked;		isicom_normal.open	= isicom_open;	isicom_normal.close	= isicom_close;	isicom_normal.write	= isicom_write;	isicom_normal.put_char	= isicom_put_char;	isicom_normal.flush_chars	= isicom_flush_chars;	isicom_normal.write_room	= isicom_write_room;	isicom_normal.chars_in_buffer	= isicom_chars_in_buffer;	isicom_normal.ioctl	= isicom_ioctl;	isicom_normal.set_termios	= isicom_set_termios;	isicom_normal.throttle	= isicom_throttle;	isicom_normal.unthrottle	= isicom_unthrottle;	isicom_normal.stop	= isicom_stop;	isicom_normal.start	= isicom_start;	isicom_normal.hangup	= isicom_hangup;	isicom_normal.flush_buffer	= isicom_flush_buffer;		/*	callout device	*/		isicom_callout	= isicom_normal;	isicom_callout.name	= "cum"; 	isicom_callout.major	= ISICOM_CMAJOR;	isicom_callout.subtype	= SERIAL_TYPE_CALLOUT;		if ((error=tty_register_driver(&isicom_normal))!=0) {		printk(KERN_DEBUG "ISICOM: Couldn't register the dialin driver, error=%d\n",			error);		return error;	}	if ((error=tty_register_driver(&isicom_callout))!=0) {		tty_unregister_driver(&isicom_normal);		printk(KERN_DEBUG "ISICOM: Couldn't register the callout driver, error=%d\n",			error);		return error;		}	return 0;}static void unregister_drivers(void){	int error;	if ((error=tty_unregister_driver(&isicom_callout))!=0)		printk(KERN_DEBUG "ISICOM: couldn't unregister callout driver error=%d.\n",error);	if (tty_unregister_driver(&isicom_normal))		printk(KERN_DEBUG "ISICOM: couldn't unregister normal driver error=%d.\n",error);}static int register_isr(void){	int count, done=0, card;	int flag;	unsigned char request;	for (count=0; count < BOARD_COUNT; count++ ) {		if (isi_card[count].base) {		/*		 * verify if the required irq has already been requested for		 * another ISI Card, if so we already have it, else request it		 */			request = YES;			for(card = 0; card < count; card++)			if ((isi_card[card].base) && (isi_card[card].irq == isi_card[count].irq)) {				request = NO;				if ((isi_card[count].isa == NO) && (isi_card[card].isa == NO))					break;				/*				 * ISA cards cannot share interrupts with other				 * PCI or ISA devices hence disable this card.				 */				release_region(isi_card[count].base,16);				isi_card[count].base = 0;				break;			}			flag=0;			if(isi_card[count].isa == NO)				flag |= SA_SHIRQ;							if (request == YES) { 				if (request_irq(isi_card[count].irq, isicom_interrupt, SA_INTERRUPT|flag, ISICOM_NAME, NULL)) {					printk(KERN_WARNING "ISICOM: Could not install handler at Irq %d. Card%d will be disabled.\n",						isi_card[count].irq, count+1);					release_region(isi_card[count].base,16);					isi_card[count].base=0;				}				else {					printk(KERN_INFO "ISICOM: Card%d at 0x%x using irq %d.\n", 					count+1, isi_card[count].base, isi_card[count].irq); 										irq_to_board[isi_card[count].irq]=&isi_card[count];					done++;				}			}		}		}	return done;}static void unregister_isr(void){	int count, card;	unsigned char freeirq;	for (count=0; count < BOARD_COUNT; count++ ) {		if (isi_card[count].base) {			freeirq = YES;			for(card = 0; card < count; card++)				if ((isi_card[card].base) && (isi_card[card].irq == isi_card[count].irq)) {					freeirq = NO;					break;				}			if (freeirq == YES) {				free_irq(isi_card[count].irq, NULL);#ifdef ISICOM_DEBUG							printk(KERN_DEBUG "ISICOM: Irq %d released for Card%d.\n",isi_card[count].irq, count+1);#endif				}				}	}}static int isicom_init(void){	int card, channel, base;	struct isi_port * port;	unsigned long page;		if (!tmp_buf) { 		page = get_free_page(GFP_KERNEL);	      	if (!page) {#ifdef ISICOM_DEBUG	      		      		printk(KERN_DEBUG "ISICOM: Couldn't allocate page for tmp_buf.\n");#else			printk(KERN_ERR "ISICOM: Not enough memory...\n");#endif	      	      		return 0;	      	}		      	tmp_buf = (unsigned char *) page;	}		if (!register_ioregion()) 	{		printk(KERN_ERR "ISICOM: All required I/O space found busy.\n");		free_page((unsigned long)tmp_buf);		return 0;	}	if (register_drivers()) 	{		unregister_ioregion();		free_page((unsigned long)tmp_buf);		return 0;	}	if (!register_isr()) 	{		unregister_drivers();		/*  ioports already uregistered in register_isr */		free_page((unsigned long)tmp_buf);		return 0;			}		/* initialize bottom half  */	init_bh(ISICOM_BH, do_isicom_bh);	memset(isi_ports, 0, sizeof(isi_ports));	for (card = 0; card < BOARD_COUNT; card++) {		port = &isi_ports[card * 16];		isi_card[card].ports = port;		base = isi_card[card].base;		for (channel = 0; channel < 16; channel++, port++) {			port->magic = ISICOM_MAGIC;			port->card = &isi_card[card];			port->channel = channel;					port->normal_termios = isicom_normal.init_termios;			port->callout_termios = isicom_callout.init_termios;		 	port->close_delay = 50 * HZ/100;		 	port->closing_wait = 3000 * HZ/100;			port->hangup_tq.routine = do_isicom_hangup;		 	port->hangup_tq.data = port;		 	port->bh_tqueue.routine = isicom_bottomhalf;		 	port->bh_tqueue.data = port;		 	port->status = 0;			init_waitqueue_head(&port->open_wait);	 							init_waitqueue_head(&port->close_wait);			/*  . . .  */ 		}	} 		return 1;	}/* *	Insmod can set static symbols so keep these static */ static int io[4];static int irq[4];MODULE_AUTHOR("MultiTech");MODULE_DESCRIPTION("Driver for the ISI series of cards by MultiTech");MODULE_PARM(io, "1-4i");MODULE_PARM_DESC(io, "I/O ports for the cards");MODULE_PARM(irq, "1-4i");MODULE_PARM_DESC(irq, "Interrupts for the cards");int init_module(void){	struct pci_dev *dev = NULL;	int retval, card, idx, count;	unsigned char pciirq;	unsigned int ioaddr;	                	card = 0;	for(idx=0; idx < BOARD_COUNT; idx++) {			if (io[idx]) {			isi_card[idx].base=io[idx];			isi_card[idx].irq=irq[idx];			isi_card[idx].isa=YES;			card++;		}		else {			isi_card[idx].base = 0;			isi_card[idx].irq = 0;		}	}		for (idx=0 ;idx < card; idx++) {		if (!((isi_card[idx].irq==2)||(isi_card[idx].irq==3)||		    (isi_card[idx].irq==4)||(isi_card[idx].irq==5)||		    (isi_card[idx].irq==7)||(isi_card[idx].irq==10)||		    (isi_card[idx].irq==11)||(isi_card[idx].irq==12)||		    (isi_card[idx].irq==15))) {						if (isi_card[idx].base) {				printk(KERN_ERR "ISICOM: Irq %d unsupported. Disabling Card%d...\n",					isi_card[idx].irq, idx+1);				isi_card[idx].base=0;				card--;			}			}	}			if (pci_present() && (card < BOARD_COUNT)) {		for (idx=0; idx < DEVID_COUNT; idx++) {			dev = NULL;			for (;;){				if (!(dev = pci_find_device(VENDOR_ID, device_id[idx], dev)))					break;				if (card >= BOARD_COUNT)					break;									if (pci_enable_device(dev))					break;				/* found a PCI ISI card! */				ioaddr = pci_resource_start (dev, 3); /* i.e at offset 0x1c in the								       * PCI configuration register								       * space.								       */				pciirq = dev->irq;				printk(KERN_INFO "ISI PCI Card(Device ID 0x%x)\n", device_id[idx]);				/*				 * allot the first empty slot in the array				 */								for (count=0; count < BOARD_COUNT; count++) {									if (isi_card[count].base == 0) {						isi_card[count].base = ioaddr;						isi_card[count].irq = pciirq;						isi_card[count].isa = NO;						card++;						break;					}				}			}							if (card >= BOARD_COUNT) break;		}	}		if (!(isi_card[0].base || isi_card[1].base || isi_card[2].base || isi_card[3].base)) {		printk(KERN_ERR "ISICOM: No valid card configuration. Driver cannot be initialized...\n"); 		return -EIO;	}			retval=misc_register(&isiloader_device);	if (retval<0) {		printk(KERN_ERR "ISICOM: Unable to register firmware loader driver.\n");		return -EIO;	}		if (!isicom_init()) {		if (misc_deregister(&isiloader_device)) 			printk(KERN_ERR "ISICOM: Unable to unregister Firmware Loader driver\n");		return -EIO;	}		init_timer(&tx);	tx.expires = jiffies + 1;	tx.data = 0;	tx.function = isicom_tx;	re_schedule = 1;	add_timer(&tx);		return 0;}void cleanup_module(void){	re_schedule = 0;	current->state = TASK_INTERRUPTIBLE;	schedule_timeout(HZ);	remove_bh(ISICOM_BH);	#ifdef ISICOM_DEBUG		printk("ISICOM: isicom_tx tx_count = %ld.\n", tx_count);#endif	#ifdef ISICOM_DEBUG	printk("ISICOM: uregistering isr ...\n");#endif		unregister_isr();#ifdef ISICOM_DEBUG		printk("ISICOM: unregistering drivers ...\n");#endif	unregister_drivers();	#ifdef ISICOM_DEBUG		printk("ISICOM: unregistering ioregion ...\n");#endif		unregister_ioregion();		#ifdef ISICOM_DEBUG		printk("ISICOM: freeing tmp_buf ...\n");#endif		free_page((unsigned long)tmp_buf);	#ifdef ISICOM_DEBUG			printk("ISICOM: unregistering firmware loader ...\n");	#endif	if (misc_deregister(&isiloader_device))		printk(KERN_ERR "ISICOM: Unable to unregister Firmware Loader driver\n");}

⌨️ 快捷键说明

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