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 + -
显示快捷键?