specialix.c

来自「linux 内核源代码」· C语言 代码 · 共 2,562 行 · 第 1/5 页

C
2,562
字号
			sx_send_break(port, HZ/4);	/* 1/4 second */		return 0;	 case TCSBRKP:	/* support for POSIX tcsendbreak() */		retval = tty_check_change(tty);		if (retval) {			func_exit();			return retval;		}		tty_wait_until_sent(tty, 0);		sx_send_break(port, arg ? arg*(HZ/10) : HZ/4);		func_exit();		return 0;	 case TIOCGSOFTCAR:		 if (put_user(C_CLOCAL(tty)?1:0, (unsigned long __user *)argp)) {			 func_exit();			 return -EFAULT;		 }		 func_exit();		return 0;	 case TIOCSSOFTCAR:		 if (get_user(arg, (unsigned long __user *) argp)) {			 func_exit();			 return -EFAULT;		 }		tty->termios->c_cflag =			((tty->termios->c_cflag & ~CLOCAL) |			(arg ? CLOCAL : 0));		func_exit();		return 0;	 case TIOCGSERIAL:		 func_exit();		return sx_get_serial_info(port, argp);	 case TIOCSSERIAL:		 func_exit();		return sx_set_serial_info(port, argp);	 default:		 func_exit();		return -ENOIOCTLCMD;	}	func_exit();	return 0;}static void sx_throttle(struct tty_struct * tty){	struct specialix_port *port = (struct specialix_port *)tty->driver_data;	struct specialix_board *bp;	unsigned long flags;	func_enter();	if (sx_paranoia_check(port, tty->name, "sx_throttle")) {		func_exit();		return;	}	bp = port_Board(port);	/* Use DTR instead of RTS ! */	if (SX_CRTSCTS (tty))		port->MSVR &= ~MSVR_DTR;	else {		/* Auch!!! I think the system shouldn't call this then. */		/* Or maybe we're supposed (allowed?) to do our side of hw		   handshake anyway, even when hardware handshake is off.		   When you see this in your logs, please report.... */		printk (KERN_ERR "sx%d: Need to throttle, but can't (hardware hs is off)\n",	                 port_No (port));	}	spin_lock_irqsave(&bp->lock, flags);	sx_out(bp, CD186x_CAR, port_No(port));	spin_unlock_irqrestore(&bp->lock, flags);	if (I_IXOFF(tty)) {		spin_unlock_irqrestore(&bp->lock, flags);		sx_wait_CCR(bp);		spin_lock_irqsave(&bp->lock, flags);		sx_out(bp, CD186x_CCR, CCR_SSCH2);		spin_unlock_irqrestore(&bp->lock, flags);		sx_wait_CCR(bp);	}	spin_lock_irqsave(&bp->lock, flags);	sx_out(bp, CD186x_MSVR, port->MSVR);	spin_unlock_irqrestore(&bp->lock, flags);	func_exit();}static void sx_unthrottle(struct tty_struct * tty){	struct specialix_port *port = (struct specialix_port *)tty->driver_data;	struct specialix_board *bp;	unsigned long flags;	func_enter();	if (sx_paranoia_check(port, tty->name, "sx_unthrottle")) {		func_exit();		return;	}	bp = port_Board(port);	spin_lock_irqsave(&port->lock, flags);	/* XXXX Use DTR INSTEAD???? */	if (SX_CRTSCTS(tty)) {		port->MSVR |= MSVR_DTR;	} /* Else clause: see remark in "sx_throttle"... */	spin_lock_irqsave(&bp->lock, flags);	sx_out(bp, CD186x_CAR, port_No(port));	spin_unlock_irqrestore(&bp->lock, flags);	if (I_IXOFF(tty)) {		spin_unlock_irqrestore(&port->lock, flags);		sx_wait_CCR(bp);		spin_lock_irqsave(&bp->lock, flags);		sx_out(bp, CD186x_CCR, CCR_SSCH1);		spin_unlock_irqrestore(&bp->lock, flags);		sx_wait_CCR(bp);		spin_lock_irqsave(&port->lock, flags);	}	spin_lock_irqsave(&bp->lock, flags);	sx_out(bp, CD186x_MSVR, port->MSVR);	spin_unlock_irqrestore(&bp->lock, flags);	spin_unlock_irqrestore(&port->lock, flags);	func_exit();}static void sx_stop(struct tty_struct * tty){	struct specialix_port *port = (struct specialix_port *)tty->driver_data;	struct specialix_board *bp;	unsigned long flags;	func_enter();	if (sx_paranoia_check(port, tty->name, "sx_stop")) {		func_exit();		return;	}	bp = port_Board(port);	spin_lock_irqsave(&port->lock, flags);	port->IER &= ~IER_TXRDY;	spin_lock_irqsave(&bp->lock, flags);	sx_out(bp, CD186x_CAR, port_No(port));	sx_out(bp, CD186x_IER, port->IER);	spin_unlock_irqrestore(&bp->lock, flags);	spin_unlock_irqrestore(&port->lock, flags);	func_exit();}static void sx_start(struct tty_struct * tty){	struct specialix_port *port = (struct specialix_port *)tty->driver_data;	struct specialix_board *bp;	unsigned long flags;	func_enter();	if (sx_paranoia_check(port, tty->name, "sx_start")) {		func_exit();		return;	}	bp = port_Board(port);	spin_lock_irqsave(&port->lock, flags);	if (port->xmit_cnt && port->xmit_buf && !(port->IER & IER_TXRDY)) {		port->IER |= IER_TXRDY;		spin_lock_irqsave(&bp->lock, flags);		sx_out(bp, CD186x_CAR, port_No(port));		sx_out(bp, CD186x_IER, port->IER);		spin_unlock_irqrestore(&bp->lock, flags);	}	spin_unlock_irqrestore(&port->lock, flags);	func_exit();}/* * 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_sx_hangup() -> tty->hangup() -> sx_hangup() * */static void do_sx_hangup(struct work_struct *work){	struct specialix_port	*port =		container_of(work, struct specialix_port, tqueue_hangup);	struct tty_struct	*tty;	func_enter();	tty = port->tty;	if (tty)		tty_hangup(tty);	/* FIXME: module removal race here */	func_exit();}static void sx_hangup(struct tty_struct * tty){	struct specialix_port *port = (struct specialix_port *)tty->driver_data;	struct specialix_board *bp;	unsigned long flags;	func_enter();	if (sx_paranoia_check(port, tty->name, "sx_hangup")) {		func_exit();		return;	}	bp = port_Board(port);	sx_shutdown_port(bp, port);	spin_lock_irqsave(&port->lock, flags);	port->event = 0;	bp->count -= port->count;	if (bp->count < 0) {		printk(KERN_ERR "sx%d: sx_hangup: bad board count: %d port: %d\n",			board_No(bp), bp->count, tty->index);		bp->count = 0;	}	port->count = 0;	port->flags &= ~ASYNC_NORMAL_ACTIVE;	port->tty = NULL;	spin_unlock_irqrestore(&port->lock, flags);	wake_up_interruptible(&port->open_wait);	func_exit();}static void sx_set_termios(struct tty_struct * tty, struct ktermios * old_termios){	struct specialix_port *port = (struct specialix_port *)tty->driver_data;	unsigned long flags;	struct specialix_board  * bp;	if (sx_paranoia_check(port, tty->name, "sx_set_termios"))		return;	if (tty->termios->c_cflag == old_termios->c_cflag &&	    tty->termios->c_iflag == old_termios->c_iflag)		return;	bp = port_Board(port);	spin_lock_irqsave(&port->lock, flags);	sx_change_speed(port_Board(port), port);	spin_unlock_irqrestore(&port->lock, flags);	if ((old_termios->c_cflag & CRTSCTS) &&	    !(tty->termios->c_cflag & CRTSCTS)) {		tty->hw_stopped = 0;		sx_start(tty);	}}static void do_softint(struct work_struct *work){	struct specialix_port	*port =		container_of(work, struct specialix_port, tqueue);	struct tty_struct	*tty;	func_enter();	if(!(tty = port->tty)) {		func_exit();		return;	}	if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &port->event)) 		tty_wakeup(tty);	func_exit();}static const struct tty_operations sx_ops = {	.open  = sx_open,	.close = sx_close,	.write = sx_write,	.put_char = sx_put_char,	.flush_chars = sx_flush_chars,	.write_room = sx_write_room,	.chars_in_buffer = sx_chars_in_buffer,	.flush_buffer = sx_flush_buffer,	.ioctl = sx_ioctl,	.throttle = sx_throttle,	.unthrottle = sx_unthrottle,	.set_termios = sx_set_termios,	.stop = sx_stop,	.start = sx_start,	.hangup = sx_hangup,	.tiocmget = sx_tiocmget,	.tiocmset = sx_tiocmset,};static int sx_init_drivers(void){	int error;	int i;	func_enter();	specialix_driver = alloc_tty_driver(SX_NBOARD * SX_NPORT);	if (!specialix_driver) {		printk(KERN_ERR "sx: Couldn't allocate tty_driver.\n");		func_exit();		return 1;	}	specialix_driver->owner = THIS_MODULE;	specialix_driver->name = "ttyW";	specialix_driver->major = SPECIALIX_NORMAL_MAJOR;	specialix_driver->type = TTY_DRIVER_TYPE_SERIAL;	specialix_driver->subtype = SERIAL_TYPE_NORMAL;	specialix_driver->init_termios = tty_std_termios;	specialix_driver->init_termios.c_cflag =		B9600 | CS8 | CREAD | HUPCL | CLOCAL;	specialix_driver->init_termios.c_ispeed = 9600;	specialix_driver->init_termios.c_ospeed = 9600;	specialix_driver->flags = TTY_DRIVER_REAL_RAW;	tty_set_operations(specialix_driver, &sx_ops);	if ((error = tty_register_driver(specialix_driver))) {		put_tty_driver(specialix_driver);		printk(KERN_ERR "sx: Couldn't register specialix IO8+ driver, error = %d\n",		       error);		func_exit();		return 1;	}	memset(sx_port, 0, sizeof(sx_port));	for (i = 0; i < SX_NPORT * SX_NBOARD; i++) {		sx_port[i].magic = SPECIALIX_MAGIC;		INIT_WORK(&sx_port[i].tqueue, do_softint);		INIT_WORK(&sx_port[i].tqueue_hangup, do_sx_hangup);		sx_port[i].close_delay = 50 * HZ/100;		sx_port[i].closing_wait = 3000 * HZ/100;		init_waitqueue_head(&sx_port[i].open_wait);		init_waitqueue_head(&sx_port[i].close_wait);		spin_lock_init(&sx_port[i].lock);	}	func_exit();	return 0;}static void sx_release_drivers(void){	func_enter();	tty_unregister_driver(specialix_driver);	put_tty_driver(specialix_driver);	func_exit();}/* * This routine must be called by kernel at boot time */static int __init specialix_init(void){	int i;	int found = 0;	func_enter();	printk(KERN_INFO "sx: Specialix IO8+ driver v" VERSION ", (c) R.E.Wolff 1997/1998.\n");	printk(KERN_INFO "sx: derived from work (c) D.Gorodchanin 1994-1996.\n");#ifdef CONFIG_SPECIALIX_RTSCTS	printk (KERN_INFO "sx: DTR/RTS pin is always RTS.\n");#else	printk (KERN_INFO "sx: DTR/RTS pin is RTS when CRTSCTS is on.\n");#endif	for (i = 0; i < SX_NBOARD; i++)		spin_lock_init(&sx_board[i].lock);	if (sx_init_drivers()) {		func_exit();		return -EIO;	}	for (i = 0; i < SX_NBOARD; i++)		if (sx_board[i].base && !sx_probe(&sx_board[i]))			found++;#ifdef CONFIG_PCI	{		struct pci_dev *pdev = NULL;		i=0;		while (i < SX_NBOARD) {			if (sx_board[i].flags & SX_BOARD_PRESENT) {				i++;				continue;			}			pdev = pci_get_device (PCI_VENDOR_ID_SPECIALIX,			                        PCI_DEVICE_ID_SPECIALIX_IO8,			                        pdev);			if (!pdev) break;			if (pci_enable_device(pdev))				continue;			sx_board[i].irq = pdev->irq;			sx_board[i].base = pci_resource_start (pdev, 2);			sx_board[i].flags |= SX_BOARD_IS_PCI;			if (!sx_probe(&sx_board[i]))				found ++;		}		/* May exit pci_get sequence early with lots of boards */		if (pdev != NULL)			pci_dev_put(pdev);	}#endif	if (!found) {		sx_release_drivers();		printk(KERN_INFO "sx: No specialix IO8+ boards detected.\n");		func_exit();		return -EIO;	}	func_exit();	return 0;}static int iobase[SX_NBOARD]  = {0,};static int irq [SX_NBOARD] = {0,};module_param_array(iobase, int, NULL, 0);module_param_array(irq, int, NULL, 0);module_param(sx_debug, int, 0);module_param(sx_rxfifo, int, 0);#ifdef SPECIALIX_TIMERmodule_param(sx_poll, int, 0);#endif/* * You can setup up to 4 boards. * by specifying "iobase=0xXXX,0xXXX ..." as insmod parameter. * You should specify the IRQs too in that case "irq=....,...". * * More than 4 boards in one computer is not possible, as the card can * only use 4 different interrupts. * */static int __init specialix_init_module(void){	int i;	func_enter();	if (iobase[0] || iobase[1] || iobase[2] || iobase[3]) {		for(i = 0; i < SX_NBOARD; i++) {			sx_board[i].base = iobase[i];			sx_board[i].irq = irq[i];			sx_board[i].count= 0;		}	}	func_exit();	return specialix_init();}static void __exit specialix_exit_module(void){	int i;	func_enter();	sx_release_drivers();	for (i = 0; i < SX_NBOARD; i++)		if (sx_board[i].flags & SX_BOARD_PRESENT)			sx_release_io_range(&sx_board[i]);#ifdef SPECIALIX_TIMER	del_timer_sync(&missed_irq_timer);#endif	func_exit();}static struct pci_device_id specialx_pci_tbl[] __devinitdata = {	{ PCI_DEVICE(PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_SPECIALIX_IO8) },	{ }};MODULE_DEVICE_TABLE(pci, specialx_pci_tbl);module_init(specialix_init_module);module_exit(specialix_exit_module);MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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