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

📄 isicom.c

📁 powerpc内核mpc8241linux系统下char驱动程序
💻 C
📖 第 1 页 / 共 4 页
字号:
	struct isi_board * card;	unsigned int line, board;	unsigned long flags;	int error;#ifdef ISICOM_DEBUG		printk(KERN_DEBUG "ISICOM: open start!!!.\n");#endif		line = MINOR(tty->device) - tty->driver.minor_start;	#ifdef ISICOM_DEBUG		printk(KERN_DEBUG "line = %d.\n", line);#endif			if ((line < 0) || (line > (PORT_COUNT-1)))		return -ENODEV;	board = BOARD(line);	#ifdef ISICOM_DEBUG		printk(KERN_DEBUG "board = %d.\n", board);#endif			card = &isi_card[board];	if (!(card->status & FIRMWARE_LOADED)) {#ifdef ISICOM_DEBUG			printk(KERN_DEBUG"ISICOM: Firmware not loaded to card%d.\n", board);#endif				return -ENODEV;	}		/*  open on higher 8 dev files on a 8 port card !!! */	if (card->port_count == 8) 		if (line > ((board * 16)+7)) {			printk(KERN_ERR "ISICOM: Opened >8 on a 8 port card.\n");			return -ENODEV;		}		port = &isi_ports[line];		if (isicom_paranoia_check(port, tty->device, "isicom_open"))		return -ENODEV;		#ifdef ISICOM_DEBUG			printk(KERN_DEBUG "ISICOM: isicom_setup_board ...\n");		#endif		isicom_setup_board(card);				port->count++;	tty->driver_data = port;	port->tty = tty;#ifdef ISICOM_DEBUG		printk(KERN_DEBUG "ISICOM: isicom_setup_port ...\n");#endif		if ((error = isicom_setup_port(port))!=0)		return error;#ifdef ISICOM_DEBUG			printk(KERN_DEBUG "ISICOM: block_til_ready ...\n");	#endif		if ((error = block_til_ready(tty, filp, port))!=0)		return error;			if ((port->count == 1) && (port->flags & ASYNC_SPLIT_TERMIOS)) {		if (tty->driver.subtype == SERIAL_TYPE_NORMAL)			*tty->termios = port->normal_termios;		else 			*tty->termios = port->callout_termios;		save_flags(flags); cli();		isicom_config_port(port);		restore_flags(flags);			}			port->session = current->session;		port->pgrp = current->pgrp;#ifdef ISICOM_DEBUG		printk(KERN_DEBUG "ISICOM: open end!!!.\n");#endif		return 0;      		} /* close et all */extern inline void isicom_shutdown_board(struct isi_board * bp){	int channel;	struct isi_port * port;		if (!(bp->status & BOARD_ACTIVE))		return;	bp->status &= ~BOARD_ACTIVE;	port = bp->ports;	for(channel = 0; channel < bp->port_count; channel++, port++) {		drop_dtr_rts(port);	}		MOD_DEC_USE_COUNT;}static void isicom_shutdown_port(struct isi_port * port){	struct isi_board * card = port->card;	struct tty_struct * tty;			if (!(port->flags & ASYNC_INITIALIZED))		return;	if (port->xmit_buf) {		free_page((unsigned long) port->xmit_buf);		port->xmit_buf = NULL;	}		if (!(tty = port->tty) || C_HUPCL(tty)) 		/* drop dtr on this port */		drop_dtr(port);			/* any other port uninits  */ 		if (tty)		set_bit(TTY_IO_ERROR, &tty->flags);	port->flags &= ~ASYNC_INITIALIZED;		if (--card->count < 0) {		printk(KERN_DEBUG "ISICOM: isicom_shutdown_port: bad board(0x%x) count %d.\n",			card->base, card->count);		card->count = 0;		}		/* last port was closed , shutdown that boad too */	if (!card->count)		isicom_shutdown_board(card);}static void isicom_close(struct tty_struct * tty, struct file * filp){	struct isi_port * port = (struct isi_port *) tty->driver_data;	struct isi_board * card = port->card;	unsigned long flags;		if (!port)		return;	if (isicom_paranoia_check(port, tty->device, "isicom_close"))		return;	#ifdef ISICOM_DEBUG			printk(KERN_DEBUG "ISICOM: Close start!!!.\n");#endif			save_flags(flags); cli();	if (tty_hung_up_p(filp)) {		restore_flags(flags);		return;	}		if ((tty->count == 1) && (port->count != 1)) {		printk(KERN_WARNING "ISICOM:(0x%x) isicom_close: bad port count"			"tty->count = 1	port count = %d.\n",			card->base, port->count);		port->count = 1;	}	if (--port->count < 0) {		printk(KERN_WARNING "ISICOM:(0x%x) isicom_close: bad port count for"			"channel%d = %d", card->base, port->channel, 			port->count);		port->count = 0;		}		if (port->count) {		restore_flags(flags);		return;	} 		port->flags |= ASYNC_CLOSING;	/* 	 * save termios struct since callout and dialin termios may be 	 * different.	 */		if (port->flags & ASYNC_NORMAL_ACTIVE)		port->normal_termios = *tty->termios;	if (port->flags & ASYNC_CALLOUT_ACTIVE)		port->callout_termios = *tty->termios;		tty->closing = 1;	if (port->closing_wait != ASYNC_CLOSING_WAIT_NONE)		tty_wait_until_sent(tty, port->closing_wait);	/* indicate to the card that no more data can be received 	   on this port */	if (port->flags & ASYNC_INITIALIZED) {   		card->port_status &= ~(1 << port->channel);		outw(card->port_status, card->base + 0x02);	}		isicom_shutdown_port(port);	if (tty->driver.flush_buffer)		tty->driver.flush_buffer(tty);	if (tty->ldisc.flush_buffer)		tty->ldisc.flush_buffer(tty);	tty->closing = 0;	port->tty = 0;	if (port->blocked_open) {		if (port->close_delay) {			current->state = TASK_INTERRUPTIBLE;#ifdef ISICOM_DEBUG						printk(KERN_DEBUG "ISICOM: scheduling until time out.\n");#endif						schedule_timeout(port->close_delay);		}		wake_up_interruptible(&port->open_wait);	}		port->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE | 			ASYNC_CLOSING);	wake_up_interruptible(&port->close_wait);	restore_flags(flags);#ifdef ISICOM_DEBUG		printk(KERN_DEBUG "ISICOM: Close end!!!.\n");#endif	}/* write et all */static int isicom_write(struct tty_struct * tty, int from_user,			const unsigned char * buf, int count){	struct isi_port * port = (struct isi_port *) tty->driver_data;	unsigned long flags;	int cnt, total = 0;#ifdef ISICOM_DEBUG	printk(KERN_DEBUG "ISICOM: isicom_write for port%d: %d bytes.\n",			port->channel+1, count);#endif	  		if (isicom_paranoia_check(port, tty->device, "isicom_write"))		return 0;		if (!tty || !port->xmit_buf || !tmp_buf)		return 0;	if (from_user)		down(&tmp_buf_sem); /* acquire xclusive access to tmp_buf */			save_flags(flags);	while(1) {			cli();		cnt = MIN(count, MIN(SERIAL_XMIT_SIZE - port->xmit_cnt - 1,			SERIAL_XMIT_SIZE - port->xmit_head));		if (cnt <= 0) 			break;				if (from_user) {			/* the following may block for paging... hence 			   enabling interrupts but tx routine may have 			   created more space in xmit_buf when the ctrl 			   gets back here  */			sti(); 			copy_from_user(tmp_buf, buf, cnt);			cli();			cnt = MIN(cnt, MIN(SERIAL_XMIT_SIZE - port->xmit_cnt - 1,			SERIAL_XMIT_SIZE - port->xmit_head));			memcpy(port->xmit_buf + port->xmit_head, tmp_buf, cnt);		}			else			memcpy(port->xmit_buf + port->xmit_head, buf, cnt);		port->xmit_head = (port->xmit_head + cnt) & (SERIAL_XMIT_SIZE - 1);		port->xmit_cnt += cnt;		restore_flags(flags);		buf += cnt;		count -= cnt;		total += cnt;	}			if (from_user)		up(&tmp_buf_sem);	if (port->xmit_cnt && !tty->stopped && !tty->hw_stopped)		port->status |= ISI_TXOK;	restore_flags(flags);#ifdef ISICOM_DEBUG	printk(KERN_DEBUG "ISICOM: isicom_write %d bytes written.\n", total);#endif			return total;	}/* put_char et all */static void isicom_put_char(struct tty_struct * tty, unsigned char ch){	struct isi_port * port = (struct isi_port *) tty->driver_data;	unsigned long flags;		if (isicom_paranoia_check(port, tty->device, "isicom_put_char"))		return;		if (!tty || !port->xmit_buf)		return;#ifdef ISICOM_DEBUG	printk(KERN_DEBUG "ISICOM: put_char, port %d, char %c.\n", port->channel+1, ch);#endif						save_flags(flags); cli();		if (port->xmit_cnt >= (SERIAL_XMIT_SIZE - 1)) {		restore_flags(flags);		return;	}		port->xmit_buf[port->xmit_head++] = ch;	port->xmit_head &= (SERIAL_XMIT_SIZE - 1);	port->xmit_cnt++;	restore_flags(flags);}/* flush_chars et all */static void isicom_flush_chars(struct tty_struct * tty){	struct isi_port * port = (struct isi_port *) tty->driver_data;		if (isicom_paranoia_check(port, tty->device, "isicom_flush_chars"))		return;		if (port->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||	    !port->xmit_buf)		return;			/* this tells the transmitter to consider this port for	   data output to the card ... that's the best we can do. */	port->status |= ISI_TXOK;	}/* write_room et all */static int isicom_write_room(struct tty_struct * tty){	struct isi_port * port = (struct isi_port *) tty->driver_data;	int free;	if (isicom_paranoia_check(port, tty->device, "isicom_write_room"))		return 0;		free = SERIAL_XMIT_SIZE - port->xmit_cnt - 1;	if (free < 0)		free = 0;	return free;}/* chars_in_buffer et all */static int isicom_chars_in_buffer(struct tty_struct * tty){	struct isi_port * port = (struct isi_port *) tty->driver_data;	if (isicom_paranoia_check(port, tty->device, "isicom_chars_in_buffer"))		return 0;	return port->xmit_cnt;}/* ioctl et all */extern inline void isicom_send_break(struct isi_port * port, unsigned long length){	struct isi_board * card = port->card;	short wait = 10;	unsigned short base = card->base;		unsigned long flags;		save_flags(flags); cli();	while (((inw(base + 0x0e) & 0x0001) == 0) && (wait-- > 0));		if (!wait) {		printk(KERN_DEBUG "ISICOM: Card found busy in isicom_send_break.\n");		return;	}		outw(0x8000 | ((port->channel) << (card->shift_count)) | 0x3, base);	outw((length & 0xff) << 8 | 0x00, base);	outw((length & 0xff00), base);	InterruptTheCard(base);	restore_flags(flags);}static int isicom_get_modem_info(struct isi_port * port, unsigned int * value){	/* just send the port status */	unsigned int info;	unsigned short status = port->status;		info =  ((status & ISI_RTS) ? TIOCM_RTS : 0) |		((status & ISI_DTR) ? TIOCM_DTR : 0) |		((status & ISI_DCD) ? TIOCM_CAR : 0) |		((status & ISI_DSR) ? TIOCM_DSR : 0) |		((status & ISI_CTS) ? TIOCM_CTS : 0) |		((status & ISI_RI ) ? TIOCM_RI  : 0);	put_user(info, (unsigned long *) value);	return 0;	}static int isicom_set_modem_info(struct isi_port * port, unsigned int cmd,					unsigned int * value){	unsigned int arg;	unsigned long flags;		if(get_user(arg, value))		return -EFAULT;		save_flags(flags); cli();		switch(cmd) {		case TIOCMBIS:			if (arg & TIOCM_RTS) 				raise_rts(port);			if (arg & TIOCM_DTR) 				raise_dtr(port);			break;				case TIOCMBIC:			if (arg & TIOCM_RTS)				drop_rts(port);			if (arg & TIOCM_DTR)				drop_dtr(port);				break;					case TIOCMSET:			if (arg & TIOCM_RTS)				raise_rts(port);			else				drop_rts(port);						if (arg & TIOCM_DTR)				raise_dtr(port);			else				drop_dtr(port);			break;				default:			restore_flags(flags);			return -EINVAL;		 		}	restore_flags(flags);	return 0;}			static int isicom_set_serial_info(struct isi_port * port,					struct serial_struct * info){	struct serial_struct newinfo;	unsigned long flags;	int reconfig_port;	if(copy_from_user(&newinfo, info, sizeof(newinfo)))		return -EFAULT;			reconfig_port = ((port->flags & ASYNC_SPD_MASK) != 			 (newinfo.flags & ASYNC_SPD_MASK));		if (!suser()) {		if ((newinfo.close_delay != port->close_delay) ||		    (newinfo.closing_wait != port->closing_wait) ||		    ((newinfo.flags & ~ASYNC_USR_MASK) != 		     (port->flags & ~ASYNC_USR_MASK)))			return -EPERM;		port->flags = ((port->flags & ~ ASYNC_USR_MASK) |				(newinfo.flags & ASYNC_USR_MASK));	}		else {		port->close_delay = newinfo.close_delay;		port->closing_wait = newinfo.closing_wait; 		port->flags = ((port->flags & ~ASYNC_FLAGS) | 				(newinfo.flags & ASYNC_FLAGS));	}	if (reconfig_port) {		save_flags(flags); cli();		isicom_config_port(port);		restore_flags(flags);	}	return 0;		 }		static int isicom_get_serial_info(struct isi_port * port, 					struct serial_struct * info){	struct serial_struct out_info;		memset(&out_info, 0, sizeof(out_info));/*	out_info.type = ? */	out_info.line = port - isi_ports;	out_info.port = port->card->base;	out_info.irq = port->card->irq;	out_info.flags = port->flags;/*	out_info.baud_base = ? */	out_info.close_delay = port->close_delay;	out_info.closing_wait = port->closing_wait;	if(copy_to_user(info, &out_info, sizeof(out_info)))		return -EFAULT;	return 0;}					static int isicom_ioctl(struct tty_struct * tty, struct file * filp,			unsigned int cmd, unsigned long arg) {	struct isi_port * port = (struct isi_port *) tty->driver_data;	int retval;	if (isicom_paranoia_check(port, tty->device, "isicom_ioctl"))		return -ENODEV;	switch(cmd) {		case TCSBRK:			retval = tty_check_change(tty);			if (retval)				return retval;			tty_wait_until_sent(tty, 0);

⌨️ 快捷键说明

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