📄 riscom8.c
字号:
copy_from_user(&tmp, newinfo, sizeof(tmp)); #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;}extern inline int rc_get_serial_info(struct riscom_port * port, struct serial_struct * retinfo){ struct serial_struct tmp; struct riscom_board *bp = port_Board(port); int error; error = verify_area(VERIFY_WRITE, (void *) retinfo, sizeof(tmp)); if (error) return error; 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; copy_to_user(retinfo, &tmp, sizeof(tmp)); return 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; int error; int retval; if (rc_paranoia_check(port, tty->device, "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 */ return 0; 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); return 0; case TIOCGSOFTCAR: return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned int *) arg); case TIOCSSOFTCAR: retval = get_user(arg,(unsigned int *) arg); if (retval) return retval; tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0)); return 0; case TIOCMGET: error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned int)); if (error) return error; return rc_get_modem_info(port, (unsigned int *) arg); case TIOCMBIS: case TIOCMBIC: case TIOCMSET: return rc_set_modem_info(port, cmd, (unsigned int *) arg); case TIOCGSERIAL: return rc_get_serial_info(port, (struct serial_struct *) arg); case TIOCSSERIAL: return rc_set_serial_info(port, (struct serial_struct *) arg); 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->device, "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->device, "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->device, "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->device, "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 scheduler tqueue when the interrupt * routine has signalled that a hangup has occurred. The path of * hangup processing is: * * serial interrupt routine -> (scheduler tqueue) -> * 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) return; tty_hangup(tty);}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->device, "rc_hangup")) return; bp = port_Board(port); rc_shutdown_port(bp, port); port->event = 0; port->count = 0; port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE); port->tty = 0; 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->device, "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_riscom_bh(void){ run_task_queue(&tq_riscom);}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)) { if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup) (tty->ldisc.write_wakeup)(tty); wake_up_interruptible(&tty->write_wait); }}static inline int rc_init_drivers(void){ int error; int i; if (!(tmp_buf = (unsigned char *) get_free_page(GFP_KERNEL))) { printk("rc: Couldn't get free page.\n"); return 1; } init_bh(RISCOM8_BH, do_riscom_bh); memset(IRQ_to_board, 0, sizeof(IRQ_to_board)); memset(&riscom_driver, 0, sizeof(riscom_driver)); riscom_driver.magic = TTY_DRIVER_MAGIC; riscom_driver.name = "ttyL"; riscom_driver.major = RISCOM8_NORMAL_MAJOR; riscom_driver.num = RC_NBOARD * RC_NPORT; riscom_driver.type = TTY_DRIVER_TYPE_SERIAL; riscom_driver.subtype = RISCOM_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; riscom_driver.refcount = &riscom_refcount; riscom_driver.table = riscom_table; riscom_driver.termios = riscom_termios; riscom_driver.termios_locked = riscom_termios_locked; riscom_driver.open = rc_open; riscom_driver.close = rc_close; riscom_driver.write = rc_write; riscom_driver.put_char = rc_put_char; riscom_driver.flush_chars = rc_flush_chars; riscom_driver.write_room = rc_write_room; riscom_driver.chars_in_buffer = rc_chars_in_buffer; riscom_driver.flush_buffer = rc_flush_buffer; riscom_driver.ioctl = rc_ioctl; riscom_driver.throttle = rc_throttle; riscom_driver.unthrottle = rc_unthrottle; riscom_driver.set_termios = rc_set_termios; riscom_driver.stop = rc_stop; riscom_driver.start = rc_start; riscom_driver.hangup = rc_hangup; riscom_callout_driver = riscom_driver; riscom_callout_driver.name = "cul"; riscom_callout_driver.major = RISCOM8_CALLOUT_MAJOR; riscom_callout_driver.subtype = RISCOM_TYPE_CALLOUT; if ((error = tty_register_driver(&riscom_driver))) { free_page((unsigned long)tmp_buf); printk("rc: Couldn't register RISCom/8 driver, error = %d\n", error); return 1; } if ((error = tty_register_driver(&riscom_callout_driver))) { free_page((unsigned long)tmp_buf); tty_unregister_driver(&riscom_driver); printk("rc: Couldn't register RISCom/8 callout 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].callout_termios = riscom_callout_driver.init_termios; rc_port[i].normal_termios = riscom_driver.init_termios; rc_port[i].magic = RISCOM8_MAGIC; rc_port[i].tqueue.routine = do_softint; rc_port[i].tqueue.data = &rc_port[i]; rc_port[i].tqueue_hangup.routine = do_rc_hangup; rc_port[i].tqueue_hangup.data = &rc_port[i]; rc_port[i].close_delay = 50 * HZ/100; rc_port[i].closing_wait = 3000 * HZ/100; } return 0;}static void rc_release_drivers(void){ unsigned long flags; save_flags(flags); cli(); remove_bh(RISCOM8_BH); free_page((unsigned long)tmp_buf); tty_unregister_driver(&riscom_driver); tty_unregister_driver(&riscom_callout_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. * */ __initfunc(void riscom8_setup(char *str, int * ints)){ int i; for (i = 0; i < RC_NBOARD; i++) { if (i < ints[0]) rc_board[i].base = ints[i+1]; else rc_board[i].base = 0; }}#endif/* * This routine must be called by kernel at boot time */__initfunc(int riscom8_init(void)){ int i; int found = 0; printk("rc: SDL RISCom/8 card driver v1.0, (c) D.Gorodchanin 1994-1996.\n"); 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("rc: No RISCom/8 boards detected.\n"); return -EIO; } return 0;}#ifdef MODULEint iobase = 0;int iobase1 = 0;int iobase2 = 0;int iobase3 = 0;MODULE_PARM(iobase, "i");MODULE_PARM(iobase1, "i");MODULE_PARM(iobase2, "i");MODULE_PARM(iobase3, "i");/* * You can setup up to 4 boards (current value of RC_NBOARD) * by specifying "iobase=0xXXX iobase1=0xXXX ..." as insmod parameter. * */int init_module(void) { 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; return riscom8_init();} void cleanup_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]); }#endif /* MODULE */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -