riscom8.c

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

C
1,842
字号
	if (!tty || !port->xmit_buf)		return;	save_flags(flags); cli();		if (port->xmit_cnt >= SERIAL_XMIT_SIZE - 1)		goto out;	port->xmit_buf[port->xmit_head++] = ch;	port->xmit_head &= SERIAL_XMIT_SIZE - 1;	port->xmit_cnt++;out:	restore_flags(flags);}static void rc_flush_chars(struct tty_struct * tty){	struct riscom_port *port = (struct riscom_port *)tty->driver_data;	unsigned long flags;					if (rc_paranoia_check(port, tty->name, "rc_flush_chars"))		return;		if (port->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||	    !port->xmit_buf)		return;	save_flags(flags); cli();	port->IER |= IER_TXRDY;	rc_out(port_Board(port), CD180_CAR, port_No(port));	rc_out(port_Board(port), CD180_IER, port->IER);	restore_flags(flags);}static int rc_write_room(struct tty_struct * tty){	struct riscom_port *port = (struct riscom_port *)tty->driver_data;	int	ret;					if (rc_paranoia_check(port, tty->name, "rc_write_room"))		return 0;	ret = SERIAL_XMIT_SIZE - port->xmit_cnt - 1;	if (ret < 0)		ret = 0;	return ret;}static int rc_chars_in_buffer(struct tty_struct *tty){	struct riscom_port *port = (struct riscom_port *)tty->driver_data;					if (rc_paranoia_check(port, tty->name, "rc_chars_in_buffer"))		return 0;		return port->xmit_cnt;}static void rc_flush_buffer(struct tty_struct *tty){	struct riscom_port *port = (struct riscom_port *)tty->driver_data;	unsigned long flags;					if (rc_paranoia_check(port, tty->name, "rc_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);	tty_wakeup(tty);}static int rc_tiocmget(struct tty_struct *tty, struct file *file){	struct riscom_port *port = (struct riscom_port *)tty->driver_data;	struct riscom_board * bp;	unsigned char status;	unsigned int result;	unsigned long flags;	if (rc_paranoia_check(port, tty->name, __FUNCTION__))		return -ENODEV;	bp = port_Board(port);	save_flags(flags); cli();	rc_out(bp, CD180_CAR, port_No(port));	status = rc_in(bp, CD180_MSVR);	result = rc_in(bp, RC_RI) & (1u << port_No(port)) ? 0 : TIOCM_RNG;	restore_flags(flags);	result |= ((status & MSVR_RTS) ? TIOCM_RTS : 0)		| ((status & MSVR_DTR) ? TIOCM_DTR : 0)		| ((status & MSVR_CD)  ? TIOCM_CAR : 0)		| ((status & MSVR_DSR) ? TIOCM_DSR : 0)		| ((status & MSVR_CTS) ? TIOCM_CTS : 0);	return result;}static int rc_tiocmset(struct tty_struct *tty, struct file *file,		       unsigned int set, unsigned int clear){	struct riscom_port *port = (struct riscom_port *)tty->driver_data;	unsigned long flags;	struct riscom_board *bp;	if (rc_paranoia_check(port, tty->name, __FUNCTION__))		return -ENODEV;	bp = port_Board(port);	save_flags(flags); cli();	if (set & TIOCM_RTS)		port->MSVR |= MSVR_RTS;	if (set & TIOCM_DTR)		bp->DTR &= ~(1u << port_No(port));	if (clear & TIOCM_RTS)		port->MSVR &= ~MSVR_RTS;	if (clear & TIOCM_DTR)		bp->DTR |= (1u << port_No(port));	rc_out(bp, CD180_CAR, port_No(port));	rc_out(bp, CD180_MSVR, port->MSVR);	rc_out(bp, RC_DTR, bp->DTR);	restore_flags(flags);	return 0;}static inline void rc_send_break(struct riscom_port * port, unsigned long length){	struct riscom_board *bp = port_Board(port);	unsigned long flags;		save_flags(flags); cli();	port->break_length = RISCOM_TPS / HZ * length;	port->COR2 |= COR2_ETC;	port->IER  |= IER_TXRDY;	rc_out(bp, CD180_CAR, port_No(port));	rc_out(bp, CD180_COR2, port->COR2);	rc_out(bp, CD180_IER, port->IER);	rc_wait_CCR(bp);	rc_out(bp, CD180_CCR, CCR_CORCHG2);	rc_wait_CCR(bp);	restore_flags(flags);}static inline int rc_set_serial_info(struct riscom_port * port,				     struct serial_struct __user * newinfo){	struct serial_struct tmp;	struct riscom_board *bp = port_Board(port);	int change_speed;	unsigned long flags;		if (copy_from_user(&tmp, newinfo, sizeof(tmp)))		return -EFAULT;	#if 0		if ((tmp.irq != bp->irq) ||	    (tmp.port != bp->base) ||	    (tmp.type != PORT_CIRRUS) ||	    (tmp.baud_base != (RC_OSCFREQ + CD180_TPC/2) / CD180_TPC) ||	    (tmp.custom_divisor != 0) ||	    (tmp.xmit_fifo_size != CD180_NFIFO) ||	    (tmp.flags & ~RISCOM_LEGAL_FLAGS))		return -EINVAL;#endif			change_speed = ((port->flags & ASYNC_SPD_MASK) !=			(tmp.flags & ASYNC_SPD_MASK));		if (!capable(CAP_SYS_ADMIN)) {		if ((tmp.close_delay != port->close_delay) ||		    (tmp.closing_wait != port->closing_wait) ||		    ((tmp.flags & ~ASYNC_USR_MASK) !=		     (port->flags & ~ASYNC_USR_MASK)))  			return -EPERM;		port->flags = ((port->flags & ~ASYNC_USR_MASK) |			       (tmp.flags & ASYNC_USR_MASK));	} else  {		port->flags = ((port->flags & ~ASYNC_FLAGS) |			       (tmp.flags & ASYNC_FLAGS));		port->close_delay = tmp.close_delay;		port->closing_wait = tmp.closing_wait;	}	if (change_speed)  {		save_flags(flags); cli();		rc_change_speed(bp, port);		restore_flags(flags);	}	return 0;}static inline int rc_get_serial_info(struct riscom_port * port,				     struct serial_struct __user *retinfo){	struct serial_struct tmp;	struct riscom_board *bp = port_Board(port);		memset(&tmp, 0, sizeof(tmp));	tmp.type = PORT_CIRRUS;	tmp.line = port - rc_port;	tmp.port = bp->base;	tmp.irq  = bp->irq;	tmp.flags = port->flags;	tmp.baud_base = (RC_OSCFREQ + CD180_TPC/2) / CD180_TPC;	tmp.close_delay = port->close_delay * HZ/100;	tmp.closing_wait = port->closing_wait * HZ/100;	tmp.xmit_fifo_size = CD180_NFIFO;	return copy_to_user(retinfo, &tmp, sizeof(tmp)) ? -EFAULT : 0;}static int rc_ioctl(struct tty_struct * tty, struct file * filp, 		    unsigned int cmd, unsigned long arg)		    {	struct riscom_port *port = (struct riscom_port *)tty->driver_data;	void __user *argp = (void __user *)arg;	int retval;					if (rc_paranoia_check(port, tty->name, "rc_ioctl"))		return -ENODEV;		switch (cmd) {	 case TCSBRK:	/* SVID version: non-zero arg --> no break */		retval = tty_check_change(tty);		if (retval)			return retval;		tty_wait_until_sent(tty, 0);		if (!arg)			rc_send_break(port, HZ/4);	/* 1/4 second */		break;	 case TCSBRKP:	/* support for POSIX tcsendbreak() */		retval = tty_check_change(tty);		if (retval)			return retval;		tty_wait_until_sent(tty, 0);		rc_send_break(port, arg ? arg*(HZ/10) : HZ/4);		break;	 case TIOCGSOFTCAR:		return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned __user *)argp);	 case TIOCSSOFTCAR:		if (get_user(arg,(unsigned __user *) argp))			return -EFAULT;		tty->termios->c_cflag =			((tty->termios->c_cflag & ~CLOCAL) |			(arg ? CLOCAL : 0));		break;	 case TIOCGSERIAL:			return rc_get_serial_info(port, argp);	 case TIOCSSERIAL:			return rc_set_serial_info(port, argp);	 default:		return -ENOIOCTLCMD;	}	return 0;}static void rc_throttle(struct tty_struct * tty){	struct riscom_port *port = (struct riscom_port *)tty->driver_data;	struct riscom_board *bp;	unsigned long flags;					if (rc_paranoia_check(port, tty->name, "rc_throttle"))		return;		bp = port_Board(port);		save_flags(flags); cli();	port->MSVR &= ~MSVR_RTS;	rc_out(bp, CD180_CAR, port_No(port));	if (I_IXOFF(tty))  {		rc_wait_CCR(bp);		rc_out(bp, CD180_CCR, CCR_SSCH2);		rc_wait_CCR(bp);	}	rc_out(bp, CD180_MSVR, port->MSVR);	restore_flags(flags);}static void rc_unthrottle(struct tty_struct * tty){	struct riscom_port *port = (struct riscom_port *)tty->driver_data;	struct riscom_board *bp;	unsigned long flags;					if (rc_paranoia_check(port, tty->name, "rc_unthrottle"))		return;		bp = port_Board(port);		save_flags(flags); cli();	port->MSVR |= MSVR_RTS;	rc_out(bp, CD180_CAR, port_No(port));	if (I_IXOFF(tty))  {		rc_wait_CCR(bp);		rc_out(bp, CD180_CCR, CCR_SSCH1);		rc_wait_CCR(bp);	}	rc_out(bp, CD180_MSVR, port->MSVR);	restore_flags(flags);}static void rc_stop(struct tty_struct * tty){	struct riscom_port *port = (struct riscom_port *)tty->driver_data;	struct riscom_board *bp;	unsigned long flags;					if (rc_paranoia_check(port, tty->name, "rc_stop"))		return;		bp = port_Board(port);		save_flags(flags); cli();	port->IER &= ~IER_TXRDY;	rc_out(bp, CD180_CAR, port_No(port));	rc_out(bp, CD180_IER, port->IER);	restore_flags(flags);}static void rc_start(struct tty_struct * tty){	struct riscom_port *port = (struct riscom_port *)tty->driver_data;	struct riscom_board *bp;	unsigned long flags;					if (rc_paranoia_check(port, tty->name, "rc_start"))		return;		bp = port_Board(port);		save_flags(flags); cli();	if (port->xmit_cnt && port->xmit_buf && !(port->IER & IER_TXRDY))  {		port->IER |= IER_TXRDY;		rc_out(bp, CD180_CAR, port_No(port));		rc_out(bp, CD180_IER, port->IER);	}	restore_flags(flags);}/* * This routine is called from the work queue when the interrupt * routine has signalled that a hangup has occurred.  The path of * hangup processing is: * * 	serial interrupt routine -> (workqueue) -> * 	do_rc_hangup() -> tty->hangup() -> rc_hangup() *  */static void do_rc_hangup(void *private_){	struct riscom_port	*port = (struct riscom_port *) private_;	struct tty_struct	*tty;		tty = port->tty;	if (tty)		tty_hangup(tty);	/* FIXME: module removal race still here */}static void rc_hangup(struct tty_struct * tty){	struct riscom_port *port = (struct riscom_port *)tty->driver_data;	struct riscom_board *bp;					if (rc_paranoia_check(port, tty->name, "rc_hangup"))		return;		bp = port_Board(port);		rc_shutdown_port(bp, port);	port->event = 0;	port->count = 0;	port->flags &= ~ASYNC_NORMAL_ACTIVE;	port->tty = NULL;	wake_up_interruptible(&port->open_wait);}static void rc_set_termios(struct tty_struct * tty, struct termios * old_termios){	struct riscom_port *port = (struct riscom_port *)tty->driver_data;	unsigned long flags;					if (rc_paranoia_check(port, tty->name, "rc_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();	rc_change_speed(port_Board(port), port);	restore_flags(flags);	if ((old_termios->c_cflag & CRTSCTS) &&	    !(tty->termios->c_cflag & CRTSCTS)) {		tty->hw_stopped = 0;		rc_start(tty);	}}static void do_softint(void *private_){	struct riscom_port	*port = (struct riscom_port *) private_;	struct tty_struct	*tty;		if(!(tty = port->tty)) 		return;	if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event)) {		tty_wakeup(tty);		wake_up_interruptible(&tty->write_wait);	}}static struct tty_operations riscom_ops = {	.open  = rc_open,	.close = rc_close,	.write = rc_write,	.put_char = rc_put_char,	.flush_chars = rc_flush_chars,	.write_room = rc_write_room,	.chars_in_buffer = rc_chars_in_buffer,	.flush_buffer = rc_flush_buffer,	.ioctl = rc_ioctl,	.throttle = rc_throttle,	.unthrottle = rc_unthrottle,	.set_termios = rc_set_termios,	.stop = rc_stop,	.start = rc_start,	.hangup = rc_hangup,	.tiocmget = rc_tiocmget,	.tiocmset = rc_tiocmset,};static inline int rc_init_drivers(void){	int error;	int i;	riscom_driver = alloc_tty_driver(RC_NBOARD * RC_NPORT);	if (!riscom_driver)			return -ENOMEM;		if (!(tmp_buf = (unsigned char *) get_zeroed_page(GFP_KERNEL))) {		printk(KERN_ERR "rc: Couldn't get free page.\n");		put_tty_driver(riscom_driver);		return 1;	}	memset(IRQ_to_board, 0, sizeof(IRQ_to_board));	riscom_driver->owner = THIS_MODULE;	riscom_driver->name = "ttyL";	riscom_driver->devfs_name = "tts/L";	riscom_driver->major = RISCOM8_NORMAL_MAJOR;	riscom_driver->type = TTY_DRIVER_TYPE_SERIAL;	riscom_driver->subtype = SERIAL_TYPE_NORMAL;	riscom_driver->init_termios = tty_std_termios;	riscom_driver->init_termios.c_cflag =		B9600 | CS8 | CREAD | HUPCL | CLOCAL;	riscom_driver->flags = TTY_DRIVER_REAL_RAW;	tty_set_operations(riscom_driver, &riscom_ops);	if ((error = tty_register_driver(riscom_driver)))  {		free_page((unsigned long)tmp_buf);		put_tty_driver(riscom_driver);		printk(KERN_ERR "rc: Couldn't register RISCom/8 driver, "				"error = %d\n",		       error);		return 1;	}	memset(rc_port, 0, sizeof(rc_port));	for (i = 0; i < RC_NPORT * RC_NBOARD; i++)  {		rc_port[i].magic = RISCOM8_MAGIC;		INIT_WORK(&rc_port[i].tqueue, do_softint, &rc_port[i]);		INIT_WORK(&rc_port[i].tqueue_hangup, do_rc_hangup, &rc_port[i]);		rc_port[i].close_delay = 50 * HZ/100;		rc_port[i].closing_wait = 3000 * HZ/100;		init_waitqueue_head(&rc_port[i].open_wait);		init_waitqueue_head(&rc_port[i].close_wait);	}		return 0;}static void rc_release_drivers(void){	unsigned long flags;	save_flags(flags);	cli();	free_page((unsigned long)tmp_buf);	tty_unregister_driver(riscom_driver);	put_tty_driver(riscom_driver);	restore_flags(flags);}#ifndef MODULE/* * Called at boot time. *  * You can specify IO base for up to RC_NBOARD cards, * using line "riscom8=0xiobase1,0xiobase2,.." at LILO prompt. * Note that there will be no probing at default * addresses in this case. * */ static int __init riscom8_setup(char *str){	int ints[RC_NBOARD];	int i;	str = get_options(str, ARRAY_SIZE(ints), ints);	for (i = 0; i < RC_NBOARD; i++) {		if (i < ints[0])			rc_board[i].base = ints[i+1];		else 			rc_board[i].base = 0;	}	return 1;}__setup("riscom8=", riscom8_setup);#endifstatic char banner[] __initdata =	KERN_INFO "rc: SDL RISCom/8 card driver v1.1, (c) D.Gorodchanin "		  "1994-1996.\n";static char no_boards_msg[] __initdata =	KERN_INFO "rc: No RISCom/8 boards detected.\n";/*  * This routine must be called by kernel at boot time  */static int __init riscom8_init(void){	int i;	int found = 0;	printk(banner);	if (rc_init_drivers()) 		return -EIO;	for (i = 0; i < RC_NBOARD; i++) 		if (rc_board[i].base && !rc_probe(&rc_board[i]))  			found++;		if (!found)  {		rc_release_drivers();		printk(no_boards_msg);		return -EIO;	}	return 0;}#ifdef MODULEstatic int iobase;static int iobase1;static int iobase2;static int iobase3;MODULE_PARM(iobase, "i");MODULE_PARM(iobase1, "i");MODULE_PARM(iobase2, "i");MODULE_PARM(iobase3, "i");MODULE_LICENSE("GPL");#endif /* MODULE *//* * You can setup up to 4 boards (current value of RC_NBOARD) * by specifying "iobase=0xXXX iobase1=0xXXX ..." as insmod parameter. * */static int __init riscom8_init_module (void){#ifdef MODULE	int i;	if (iobase || iobase1 || iobase2 || iobase3) {		for(i = 0; i < RC_NBOARD; i++)			rc_board[0].base = 0;	}	if (iobase)		rc_board[0].base = iobase;	if (iobase1)		rc_board[1].base = iobase1;	if (iobase2)		rc_board[2].base = iobase2;	if (iobase3)		rc_board[3].base = iobase3;#endif /* MODULE */	return riscom8_init();}	static void __exit riscom8_exit_module (void){	int i;		rc_release_drivers();	for (i = 0; i < RC_NBOARD; i++)  		if (rc_board[i].flags & RC_BOARD_PRESENT) 			rc_release_io_range(&rc_board[i]);	}module_init(riscom8_init_module);module_exit(riscom8_exit_module);

⌨️ 快捷键说明

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