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

📄 isicom.c

📁 powerpc内核mpc8241linux系统下char驱动程序
💻 C
📖 第 1 页 / 共 4 页
字号:
 static void isicom_bottomhalf(void * data){	struct isi_port * port = (struct isi_port *) data;	struct tty_struct * tty = port->tty;		if (!tty)		return;		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&	    tty->ldisc.write_wakeup)		(tty->ldisc.write_wakeup)(tty);	wake_up_interruptible(&tty->write_wait);} 		 		/* main interrupt handler routine */ 		static void isicom_interrupt(int irq, void * dev_id, struct pt_regs * regs){	struct isi_board * card;	struct isi_port * port;	struct tty_struct * tty;	unsigned short base, header, word_count, count;	unsigned char channel;	short byte_count;		card = irq_to_board[irq];	if (!card || !(card->status & FIRMWARE_LOADED)) {		printk(KERN_DEBUG "ISICOM: interrupt: not handling irq%d!.\n", irq);		return;	}	base = card->base;		inw(base);		/* get the dummy word out */	header = inw(base);	channel = (header & 0x7800) >> card->shift_count;	byte_count = header & 0xff;#ifdef ISICOM_DEBUG		printk(KERN_DEBUG "ISICOM:Intr:(0x%x:%d).\n", base, channel+1);#endif		if ((channel+1) > card->port_count) {		printk(KERN_WARNING "ISICOM: isicom_interrupt(0x%x): %d(channel) > port_count.\n",				base, channel+1);		ClearInterrupt(base);				return;				}	port = card->ports + channel;	if (!(port->flags & ASYNC_INITIALIZED)) {		ClearInterrupt(base);		return;	}				tty = port->tty;		if (header & 0x8000) {		/* Status Packet */		header = inw(base);		switch(header & 0xff) {			case 0:	/* Change in EIA signals */								if (port->flags & ASYNC_CHECK_CD) {					if (port->status & ISI_DCD) {						if (!(header & ISI_DCD)) {						/* Carrier has been lost  */#ifdef ISICOM_DEBUG													printk(KERN_DEBUG "ISICOM: interrupt: DCD->low.\n");#endif														port->status &= ~ISI_DCD;							if (!((port->flags & ASYNC_CALLOUT_ACTIVE) &&								(port->flags & ASYNC_CALLOUT_NOHUP)))								queue_task(&port->hangup_tq,									&tq_scheduler);						}					}					else {						if (header & ISI_DCD) {						/* Carrier has been detected */#ifdef ISICOM_DEBUG							printk(KERN_DEBUG "ISICOM: interrupt: DCD->high.\n");#endif														port->status |= ISI_DCD;							wake_up_interruptible(&port->open_wait);						}					}				}				else {					if (header & ISI_DCD) 						port->status |= ISI_DCD;					else						port->status &= ~ISI_DCD;				}									if (port->flags & ASYNC_CTS_FLOW) {					if (port->tty->hw_stopped) {						if (header & ISI_CTS) {							port->tty->hw_stopped = 0;							/* start tx ing */							port->status |= (ISI_TXOK | ISI_CTS);							schedule_bh(port);						}					}					else {						if (!(header & ISI_CTS)) {							port->tty->hw_stopped = 1;							/* stop tx ing */							port->status &= ~(ISI_TXOK | ISI_CTS);						}					}				}				else {					if (header & ISI_CTS) 						port->status |= ISI_CTS;					else						port->status &= ~ISI_CTS;				}								if (header & ISI_DSR) 					port->status |= ISI_DSR;				else					port->status &= ~ISI_DSR;								if (header & ISI_RI) 					port->status |= ISI_RI;				else					port->status &= ~ISI_RI;														break;							case 1:	/* Received Break !!!	 */				if (tty->flip.count >= TTY_FLIPBUF_SIZE)					break;				*tty->flip.flag_buf_ptr++ = TTY_BREAK;				/* dunno if this is right */					*tty->flip.char_buf_ptr++ = 0;				tty->flip.count++;				if (port->flags & ASYNC_SAK)					do_SAK(tty);				queue_task(&tty->flip.tqueue, &tq_timer);				break;							case 2:	/* Statistics		 */				printk(KERN_DEBUG "ISICOM: isicom_interrupt: stats!!!.\n");							break;							default:				printk(KERN_WARNING "ISICOM: Intr: Unknown code in status packet.\n");				break;		}	 	}	else {				/* Data   Packet */		count = MIN(byte_count, (TTY_FLIPBUF_SIZE - tty->flip.count));#ifdef ISICOM_DEBUG		printk(KERN_DEBUG "ISICOM: Intr: Can rx %d of %d bytes.\n", 					count, byte_count);#endif					word_count = count >> 1;		insw(base, tty->flip.char_buf_ptr, word_count);		tty->flip.char_buf_ptr += (word_count << 1);				byte_count -= (word_count << 1);		if (count & 0x0001) {			*tty->flip.char_buf_ptr++ = (char)(inw(base) & 0xff);			byte_count -= 2;		}			memset(tty->flip.flag_buf_ptr, 0, count);		tty->flip.flag_buf_ptr += count;		tty->flip.count += count;				if (byte_count > 0) {			printk(KERN_DEBUG "ISICOM: Intr(0x%x:%d): Flip buffer overflow! dropping bytes...\n",					base, channel+1);			while(byte_count > 0) { /* drain out unread xtra data */				inw(base);				byte_count -= 2;			}		}		queue_task(&tty->flip.tqueue, &tq_timer);	}	ClearInterrupt(base);	return;}  /* called with interrupts disabled */ static void isicom_config_port(struct isi_port * port){	struct isi_board * card = port->card;	struct tty_struct * tty;	unsigned long baud;	unsigned short channel_setup, wait, base = card->base;	unsigned short channel = port->channel, shift_count = card->shift_count;	unsigned char flow_ctrl;		if (!(tty = port->tty) || !tty->termios)		return;	baud = C_BAUD(tty);	if (baud & CBAUDEX) {		baud &= ~CBAUDEX;				/*  if CBAUDEX bit is on and the baud is set to either 50 or 75		 *  then the card is programmed for 57.6Kbps or 115Kbps		 *  respectively.		 */   		 		if (baud < 1 || baud > 2)			port->tty->termios->c_cflag &= ~CBAUDEX;		else			baud += 15;	}		if (baud == 15) {			/*  the ASYNC_SPD_HI and ASYNC_SPD_VHI options are set 		 *  by the set_serial_info ioctl ... this is done by		 *  the 'setserial' utility.		 */  					if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)			baud++;     /*  57.6 Kbps */		if ((port->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)			baud +=2;   /*  115  Kbps */	 	}	if (linuxb_to_isib[baud] == -1) {		/* hang up */	 	drop_dtr(port);	 	return;	}		else  		raise_dtr(port);			wait = 100;		while (((inw(base + 0x0e) & 0x0001) == 0) && (wait-- > 0));		if (!wait) {		printk(KERN_WARNING "ISICOM: Card found busy in isicom_config_port at channel setup.\n");		return;	}			 	outw(0x8000 | (channel << shift_count) |0x03, base);	outw(linuxb_to_isib[baud] << 8 | 0x03, base);	channel_setup = 0;	switch(C_CSIZE(tty)) {		case CS5:			channel_setup |= ISICOM_CS5;			break;		case CS6:			channel_setup |= ISICOM_CS6;			break;		case CS7:			channel_setup |= ISICOM_CS7;			break;		case CS8:			channel_setup |= ISICOM_CS8;			break;	}			if (C_CSTOPB(tty))		channel_setup |= ISICOM_2SB;		if (C_PARENB(tty))		channel_setup |= ISICOM_EVPAR;	if (C_PARODD(tty))		channel_setup |= ISICOM_ODPAR;		outw(channel_setup, base);		InterruptTheCard(base);		if (C_CLOCAL(tty))		port->flags &= ~ASYNC_CHECK_CD;	else		port->flags |= ASYNC_CHECK_CD;			/* flow control settings ...*/	flow_ctrl = 0;	port->flags &= ~ASYNC_CTS_FLOW;	if (C_CRTSCTS(tty)) {		port->flags |= ASYNC_CTS_FLOW;		flow_ctrl |= ISICOM_CTSRTS;	}		if (I_IXON(tty))			flow_ctrl |= ISICOM_RESPOND_XONXOFF;	if (I_IXOFF(tty))		flow_ctrl |= ISICOM_INITIATE_XONXOFF;				wait = 100;		while (((inw(base + 0x0e) & 0x0001) == 0) && (wait-- > 0));		if (!wait) {		printk(KERN_WARNING "ISICOM: Card found busy in isicom_config_port at flow setup.\n");		return;	}			 	outw(0x8000 | (channel << shift_count) |0x04, base);	outw(flow_ctrl << 8 | 0x05, base);	outw((STOP_CHAR(tty)) << 8 | (START_CHAR(tty)), base);	InterruptTheCard(base);		/*	rx enabled -> enable port for rx on the card	*/	if (C_CREAD(tty)) {		card->port_status |= (1 << channel);		outw(card->port_status, base + 0x02);	}		} /* open et all */ extern inline void isicom_setup_board(struct isi_board * bp){	int channel;	struct isi_port * port;	unsigned long flags;		if (bp->status & BOARD_ACTIVE) 		return;	port = bp->ports;#ifdef ISICOM_DEBUG		printk(KERN_DEBUG "ISICOM: setup_board: drop_dtr_rts start, port_count %d...\n", bp->port_count);#endif	for(channel = 0; channel < bp->port_count; channel++, port++) {		save_flags(flags); cli();		drop_dtr_rts(port);		restore_flags(flags);	}#ifdef ISICOM_DEBUG			printk(KERN_DEBUG "ISICOM: setup_board: drop_dtr_rts stop...\n");	#endif			bp->status |= BOARD_ACTIVE;	MOD_INC_USE_COUNT;	return;} static int isicom_setup_port(struct isi_port * port){	struct isi_board * card = port->card;	unsigned long flags;		if (port->flags & ASYNC_INITIALIZED)		return 0;	if (!port->xmit_buf) {		unsigned long page;				if (!(page = get_free_page(GFP_KERNEL)))			return -ENOMEM;				if (port->xmit_buf) {			free_page(page);			return -ERESTARTSYS;		}		port->xmit_buf = (unsigned char *) page;		}		save_flags(flags); cli();	if (port->tty)		clear_bit(TTY_IO_ERROR, &port->tty->flags);	if (port->count == 1)		card->count++;			port->xmit_cnt = port->xmit_head = port->xmit_tail = 0;		/*	discard any residual data	*/	kill_queue(port, ISICOM_KILLTX | ISICOM_KILLRX);		isicom_config_port(port);	port->flags |= ASYNC_INITIALIZED;		restore_flags(flags);		return 0;		}  static int block_til_ready(struct tty_struct * tty, struct file * filp, struct isi_port * port) {	int do_clocal = 0, retval;	struct wait_queue wait = { current, NULL };	/* block if port is in the process of being closed */	if (tty_hung_up_p(filp) || port->flags & ASYNC_CLOSING) {#ifdef ISICOM_DEBUG			printk(KERN_DEBUG "ISICOM: block_til_ready: close in progress.\n");#endif				interruptible_sleep_on(&port->close_wait);		if (port->flags & ASYNC_HUP_NOTIFY)			return -EAGAIN;		else			return -ERESTARTSYS;	}		/* trying to open a callout device... check for constraints */		if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) {#ifdef ISICOM_DEBUG		printk(KERN_DEBUG "ISICOM: bl_ti_rdy: callout open.\n");	#endif				if (port->flags & ASYNC_NORMAL_ACTIVE)			return -EBUSY;		if ((port->flags & ASYNC_CALLOUT_ACTIVE) &&		    (port->flags & ASYNC_SESSION_LOCKOUT) &&		    (port->session != current->session))			return -EBUSY;					if ((port->flags & ASYNC_CALLOUT_ACTIVE) &&		    (port->flags & ASYNC_PGRP_LOCKOUT) &&		    (port->pgrp != current->pgrp))			return -EBUSY;		port->flags |= ASYNC_CALLOUT_ACTIVE;		cli();		raise_dtr_rts(port);		sti();		return 0;	}		/* if non-blocking mode is set ... */		if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) {#ifdef ISICOM_DEBUG			printk(KERN_DEBUG "ISICOM: block_til_ready: non-block mode.\n");#endif				if (port->flags & ASYNC_CALLOUT_ACTIVE)			return -EBUSY;		port->flags |= ASYNC_NORMAL_ACTIVE;		return 0;		}			if (port->flags & ASYNC_CALLOUT_ACTIVE) {		if (port->normal_termios.c_cflag & CLOCAL)			do_clocal = 1; 	} else {		if (C_CLOCAL(tty))			do_clocal = 1;	}#ifdef ISICOM_DEBUG		if (do_clocal)		printk(KERN_DEBUG "ISICOM: block_til_ready: CLOCAL set.\n");#endif 				/* block waiting for DCD to be asserted, and while 						callout dev is busy */	retval = 0;	add_wait_queue(&port->open_wait, &wait);	cli();		if (!tty_hung_up_p(filp))			port->count--;	sti();	port->blocked_open++;#ifdef ISICOM_DEBUG		printk(KERN_DEBUG "ISICOM: block_til_ready: waiting for DCD...\n");#endif		while (1) {		cli();		if (!(port->flags & ASYNC_CALLOUT_ACTIVE)) 			raise_dtr_rts(port);				sti();		current->state = TASK_INTERRUPTIBLE;		if (tty_hung_up_p(filp) || !(port->flags & ASYNC_INITIALIZED)) { 				if (port->flags & ASYNC_HUP_NOTIFY)				retval = -EAGAIN;			else				retval = -ERESTARTSYS;#ifdef ISICOM_DEBUG							printk(KERN_DEBUG "ISICOM: block_til_ready: tty_hung_up_p || not init.\n"); #endif						break;		}			if (!(port->flags & ASYNC_CALLOUT_ACTIVE) &&		    !(port->flags & ASYNC_CLOSING) &&		    (do_clocal || (port->status & ISI_DCD))) {#ifdef ISICOM_DEBUG		    		 	printk(KERN_DEBUG "ISICOM: block_til_ready: do_clocal || DCD.\n");   #endif		 				break;		}			if (signal_pending(current)) {#ifdef ISICOM_DEBUG					printk(KERN_DEBUG "ISICOM: block_til_ready: sig blocked.\n");#endif						retval = -ERESTARTSYS;			break;		}		schedule();			}	current->state = TASK_RUNNING;	remove_wait_queue(&port->open_wait, &wait);	if (!tty_hung_up_p(filp))		port->count++;	port->blocked_open--;	if (retval)		return retval;	port->flags |= ASYNC_NORMAL_ACTIVE;	return 0;} static int isicom_open(struct tty_struct * tty, struct file * filp){	struct isi_port * port;

⌨️ 快捷键说明

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