📄 rio_linux.c
字号:
if (++nintr > IRQ_RATE_LIMIT) { free_irq(HostP->Ivec, ptr); printk(KERN_ERR "rio: Too many interrupts. Turning off interrupt %d.\n", HostP->Ivec); } } else { lastjif = jiffies; nintr = 0; } }#endif rio_dprintk(RIO_DEBUG_IFLOW, "rio: We've have noticed the interrupt\n"); if (HostP->Ivec == irq) { /* Tell the card we've noticed the interrupt. */ rio_reset_interrupt(HostP); } if ((HostP->Flags & RUN_STATE) != RC_RUNNING) return IRQ_HANDLED; if (test_and_set_bit(RIO_BOARD_INTR_LOCK, &HostP->locks)) { printk(KERN_ERR "Recursive interrupt! (host %d/irq%d)\n", (int) ptr, HostP->Ivec); return IRQ_HANDLED; } RIOServiceHost(p, HostP, irq); rio_dprintk(RIO_DEBUG_IFLOW, "riointr() doing host %d type %d\n", (int) ptr, HostP->Type); clear_bit(RIO_BOARD_INTR_LOCK, &HostP->locks); rio_dprintk(RIO_DEBUG_IFLOW, "rio: exit rio_interrupt (%d/%d)\n", irq, HostP->Ivec); func_exit(); return IRQ_HANDLED;}static void rio_pollfunc(unsigned long data){ func_enter(); rio_interrupt(0, &p->RIOHosts[data], NULL); p->RIOHosts[data].timer.expires = jiffies + rio_poll; add_timer(&p->RIOHosts[data].timer); func_exit();}/* ********************************************************************** * * Here are the routines that actually * * interface with the generic_serial driver * * ********************************************************************** *//* Ehhm. I don't know how to fiddle with interrupts on the Specialix cards. .... Hmm. Ok I figured it out. You don't. -- REW */static void rio_disable_tx_interrupts(void *ptr){ func_enter(); /* port->gs.flags &= ~GS_TX_INTEN; */ func_exit();}static void rio_enable_tx_interrupts(void *ptr){ struct Port *PortP = ptr; /* int hn; */ func_enter(); /* hn = PortP->HostP - p->RIOHosts; rio_dprintk (RIO_DEBUG_TTY, "Pushing host %d\n", hn); rio_interrupt (-1,(void *) hn, NULL); */ RIOTxEnable((char *) PortP); /* * In general we cannot count on "tx empty" interrupts, although * the interrupt routine seems to be able to tell the difference. */ PortP->gs.flags &= ~GS_TX_INTEN; func_exit();}static void rio_disable_rx_interrupts(void *ptr){ func_enter(); func_exit();}static void rio_enable_rx_interrupts(void *ptr){ /* struct rio_port *port = ptr; */ func_enter(); func_exit();}/* Jeez. Isn't this simple? */static int rio_get_CD(void *ptr){ struct Port *PortP = ptr; int rv; func_enter(); rv = (PortP->ModemState & MSVR1_CD) != 0; rio_dprintk(RIO_DEBUG_INIT, "Getting CD status: %d\n", rv); func_exit(); return rv;}/* Jeez. Isn't this simple? Actually, we can sync with the actual port by just pushing stuff into the queue going to the port... */static int rio_chars_in_buffer(void *ptr){ func_enter(); func_exit(); return 0;}/* Nothing special here... */static void rio_shutdown_port(void *ptr){ struct Port *PortP; func_enter(); PortP = (struct Port *) ptr; PortP->gs.tty = NULL; func_exit();}/* I haven't the foggiest why the decrement use count has to happen here. The whole linux serial drivers stuff needs to be redesigned. My guess is that this is a hack to minimize the impact of a bug elsewhere. Thinking about it some more. (try it sometime) Try running minicom on a serial port that is driven by a modularized driver. Have the modem hangup. Then remove the driver module. Then exit minicom. I expect an "oops". -- REW */static void rio_hungup(void *ptr){ struct Port *PortP; func_enter(); PortP = (struct Port *) ptr; PortP->gs.tty = NULL; func_exit();}/* The standard serial_close would become shorter if you'd wrap it like this. rs_close (...){save_flags;cli;real_close();dec_use_count;restore_flags;} */static void rio_close(void *ptr){ struct Port *PortP; func_enter(); PortP = (struct Port *) ptr; riotclose(ptr); if (PortP->gs.count) { printk(KERN_ERR "WARNING port count:%d\n", PortP->gs.count); PortP->gs.count = 0; } PortP->gs.tty = NULL; func_exit();}static int rio_fw_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg){ int rc = 0; func_enter(); /* The "dev" argument isn't used. */ rc = riocontrol(p, 0, cmd, (void *) arg, capable(CAP_SYS_ADMIN)); func_exit(); return rc;}extern int RIOShortCommand(struct rio_info *p, struct Port *PortP, int command, int len, int arg);static int rio_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd, unsigned long arg){ int rc; struct Port *PortP; int ival; func_enter(); PortP = (struct Port *) tty->driver_data; rc = 0; switch (cmd) { case TIOCSSOFTCAR: if ((rc = get_user(ival, (unsigned int *) arg)) == 0) { tty->termios->c_cflag = (tty->termios->c_cflag & ~CLOCAL) | (ival ? CLOCAL : 0); } break; case TIOCGSERIAL: rc = -EFAULT; if (access_ok(VERIFY_WRITE, (void *) arg, sizeof(struct serial_struct))) rc = gs_getserial(&PortP->gs, (struct serial_struct *) arg); break; case TCSBRK: if (PortP->State & RIO_DELETED) { rio_dprintk(RIO_DEBUG_TTY, "BREAK on deleted RTA\n"); rc = -EIO; } else { if (RIOShortCommand(p, PortP, SBREAK, 2, 250) == RIO_FAIL) { rio_dprintk(RIO_DEBUG_INTR, "SBREAK RIOShortCommand failed\n"); rc = -EIO; } } break; case TCSBRKP: if (PortP->State & RIO_DELETED) { rio_dprintk(RIO_DEBUG_TTY, "BREAK on deleted RTA\n"); rc = -EIO; } else { int l; l = arg ? arg * 100 : 250; if (l > 255) l = 255; if (RIOShortCommand(p, PortP, SBREAK, 2, arg ? arg * 100 : 250) == RIO_FAIL) { rio_dprintk(RIO_DEBUG_INTR, "SBREAK RIOShortCommand failed\n"); rc = -EIO; } } break; case TIOCSSERIAL: rc = -EFAULT; if (access_ok(VERIFY_READ, (void *) arg, sizeof(struct serial_struct))) rc = gs_setserial(&PortP->gs, (struct serial_struct *) arg); break; default: rc = -ENOIOCTLCMD; break; } func_exit(); return rc;}/* The throttle/unthrottle scheme for the Specialix card is different * from other drivers and deserves some explanation. * The Specialix hardware takes care of XON/XOFF * and CTS/RTS flow control itself. This means that all we have to * do when signalled by the upper tty layer to throttle/unthrottle is * to make a note of it here. When we come to read characters from the * rx buffers on the card (rio_receive_chars()) we look to see if the * upper layer can accept more (as noted here in rio_rx_throt[]). * If it can't we simply don't remove chars from the cards buffer. * When the tty layer can accept chars, we again note that here and when * rio_receive_chars() is called it will remove them from the cards buffer. * The card will notice that a ports buffer has drained below some low * water mark and will unflow control the line itself, using whatever * flow control scheme is in use for that port. -- Simon Allen */static void rio_throttle(struct tty_struct *tty){ struct Port *port = (struct Port *) tty->driver_data; func_enter(); /* If the port is using any type of input flow * control then throttle the port. */ if ((tty->termios->c_cflag & CRTSCTS) || (I_IXOFF(tty))) { port->State |= RIO_THROTTLE_RX; } func_exit();}static void rio_unthrottle(struct tty_struct *tty){ struct Port *port = (struct Port *) tty->driver_data; func_enter(); /* Always unthrottle even if flow control is not enabled on * this port in case we disabled flow control while the port * was throttled */ port->State &= ~RIO_THROTTLE_RX; func_exit(); return;}/* ********************************************************************** * * Here are the initialization routines. * * ********************************************************************** */static struct vpd_prom *get_VPD_PROM(struct Host *hp){ static struct vpd_prom vpdp; char *p; int i; func_enter(); rio_dprintk(RIO_DEBUG_PROBE, "Going to verify vpd prom at %p.\n", hp->Caddr + RIO_VPD_ROM); p = (char *) &vpdp; for (i = 0; i < sizeof(struct vpd_prom); i++) *p++ = readb(hp->Caddr + RIO_VPD_ROM + i * 2); /* read_rio_byte (hp, RIO_VPD_ROM + i*2); */ /* Terminate the identifier string. *** requires one extra byte in struct vpd_prom *** */ *p++ = 0; if (rio_debug & RIO_DEBUG_PROBE) my_hd((char *) &vpdp, 0x20); func_exit(); return &vpdp;}static struct tty_operations rio_ops = { .open = riotopen, .close = gs_close, .write = gs_write, .put_char = gs_put_char, .flush_chars = gs_flush_chars, .write_room = gs_write_room, .chars_in_buffer = gs_chars_in_buffer, .flush_buffer = gs_flush_buffer, .ioctl = rio_ioctl, .throttle = rio_throttle, .unthrottle = rio_unthrottle, .set_termios = gs_set_termios, .stop = gs_stop, .start = gs_start, .hangup = gs_hangup,};static int rio_init_drivers(void){ int error = -ENOMEM; rio_driver = alloc_tty_driver(256); if (!rio_driver) goto out; rio_driver2 = alloc_tty_driver(256); if (!rio_driver2) goto out1; func_enter(); rio_driver->owner = THIS_MODULE; rio_driver->driver_name = "specialix_rio"; rio_driver->name = "ttySR"; rio_driver->major = RIO_NORMAL_MAJOR0; rio_driver->type = TTY_DRIVER_TYPE_SERIAL; rio_driver->subtype = SERIAL_TYPE_NORMAL; rio_driver->init_termios = tty_std_termios; rio_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; rio_driver->flags = TTY_DRIVER_REAL_RAW; tty_set_operations(rio_driver, &rio_ops); rio_driver2->owner = THIS_MODULE; rio_driver2->driver_name = "specialix_rio"; rio_driver2->name = "ttySR"; rio_driver2->major = RIO_NORMAL_MAJOR1; rio_driver2->type = TTY_DRIVER_TYPE_SERIAL; rio_driver2->subtype = SERIAL_TYPE_NORMAL; rio_driver2->init_termios = tty_std_termios; rio_driver2->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; rio_driver2->flags = TTY_DRIVER_REAL_RAW; tty_set_operations(rio_driver2, &rio_ops); rio_dprintk(RIO_DEBUG_INIT, "set_termios = %p\n", gs_set_termios); if ((error = tty_register_driver(rio_driver))) goto out2; if ((error = tty_register_driver(rio_driver2))) goto out3; func_exit(); return 0; out3: tty_unregister_driver(rio_driver); out2: put_tty_driver(rio_driver2); out1: put_tty_driver(rio_driver); out: printk(KERN_ERR "rio: Couldn't register a rio driver, error = %d\n", error); return 1;}static void *ckmalloc(int size){ void *p; p = kmalloc(size, GFP_KERNEL);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -