isicom.c

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

C
1,938
字号
		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 a port greater than the port count for the card !!! */	if (line > ((board * 16) + card->port_count - 1)) {		printk(KERN_ERR "ISICOM: Open on a port which exceeds the port_count of the card!\n");		return -ENODEV;	}		port = &isi_ports[line];		if (isicom_paranoia_check(port, tty->name, "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;#ifdef ISICOM_DEBUG		printk(KERN_DEBUG "ISICOM: open end!!!.\n");#endif		return 0;      		} /* close et all */static 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);	}	}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->name, "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;	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);			tty_ldisc_flush(tty);	tty->closing = 0;	port->tty = NULL;	if (port->blocked_open) {		if (port->close_delay) {			set_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_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->name, "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_t(int, 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(); 			if (copy_from_user(tmp_buf, buf, cnt)) {				up(&tmp_buf_sem);				restore_flags(flags);				return -EFAULT;			}			cli();			cnt = min_t(int, 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->name, "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->name, "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->name, "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->name, "isicom_chars_in_buffer"))		return 0;	return port->xmit_cnt;}/* ioctl et all */static 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");		goto out;	}		outw(0x8000 | ((port->channel) << (card->shift_count)) | 0x3, base);	outw((length & 0xff) << 8 | 0x00, base);	outw((length & 0xff00), base);	InterruptTheCard(base);out:	restore_flags(flags);}static int isicom_tiocmget(struct tty_struct *tty, struct file *file){	struct isi_port * port = (struct isi_port *) tty->driver_data;	/* just send the port status */	unsigned short status = port->status;	if (isicom_paranoia_check(port, tty->name, "isicom_ioctl"))		return -ENODEV;		return  ((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);}static int isicom_tiocmset(struct tty_struct *tty, struct file *file,			   unsigned int set, unsigned int clear){	struct isi_port * port = (struct isi_port *) tty->driver_data;	unsigned long flags;		if (isicom_paranoia_check(port, tty->name, "isicom_ioctl"))		return -ENODEV;		save_flags(flags); cli();	if (set & TIOCM_RTS)		raise_rts(port);	if (set & TIOCM_DTR)		raise_dtr(port);	if (clear & TIOCM_RTS)		drop_rts(port);	if (clear & TIOCM_DTR)		drop_dtr(port);	restore_flags(flags);	return 0;}			static int isicom_set_serial_info(struct isi_port * port,					struct serial_struct __user *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 (!capable(CAP_SYS_ADMIN)) {		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 __user *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;	void __user *argp = (void __user *)arg;	int retval;	if (isicom_paranoia_check(port, tty->name, "isicom_ioctl"))		return -ENODEV;	switch(cmd) {		case TCSBRK:			retval = tty_check_change(tty);			if (retval)				return retval;			tty_wait_until_sent(tty, 0);			if (!arg)				isicom_send_break(port, HZ/4);			return 0;					case TCSBRKP:				retval = tty_check_change(tty);			if (retval)				return retval;			tty_wait_until_sent(tty, 0);			isicom_send_break(port, arg ? arg * (HZ/10) : HZ/4);			return 0;					case TIOCGSOFTCAR:			return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long __user *)argp);					case TIOCSSOFTCAR:			if(get_user(arg, (unsigned long __user *) argp))				return -EFAULT;			tty->termios->c_cflag =				((tty->termios->c_cflag & ~CLOCAL) |				(arg ? CLOCAL : 0));			return 0;						case TIOCGSERIAL:			return isicom_get_serial_info(port, argp);				case TIOCSSERIAL:			return isicom_set_serial_info(port, argp);							default:			return -ENOIOCTLCMD;							}	return 0;}/* set_termios et all */static void isicom_set_termios(struct tty_struct * tty, struct termios * old_termios){	struct isi_port * port = (struct isi_port *) tty->driver_data;	unsigned long flags;		if (isicom_paranoia_check(port, tty->name, "isicom_set_termios"))		return;		if (tty->termios->c_cflag == old_termios->c_cflag &&	    tty->termios->c_iflag == old_termios->c_iflag)		return;			save_flags(flags); cli();

⌨️ 快捷键说明

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