📄 rio_linux.c
字号:
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; 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; } 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 ();}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;#if 0 port->gs.flags &= ~ GS_ACTIVE; if (!port->gs.tty) { rio_dprintk (RIO_DBUG_TTY, "No tty.\n"); return; } if (!port->gs.tty->termios) { rio_dprintk (RIO_DEBUG_TTY, "No termios.\n"); return; } if (port->gs.tty->termios->c_cflag & HUPCL) { rio_setsignals (port, 0, 0); }#endif 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; rio_dec_mod_count (); 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; rio_dec_mod_count (); 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, suser ()); 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) {#if 0 case TIOCGSOFTCAR: rc = Put_user(((tty->termios->c_cflag & CLOCAL) ? 1 : 0), (unsigned int *) arg); break;#endif case TIOCSSOFTCAR: if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(int))) == 0) { Get_user(ival, (unsigned int *) arg); tty->termios->c_cflag = (tty->termios->c_cflag & ~CLOCAL) | (ival ? CLOCAL : 0); } break; case TIOCGSERIAL: if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(struct serial_struct))) == 0) 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: if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(struct serial_struct))) == 0) rc = gs_setserial(&PortP->gs, (struct serial_struct *) arg); break;#if 0 case TIOCMGET: if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned int))) == 0) { ival = rio_getsignals(port); put_user(ival, (unsigned int *) arg); } break; case TIOCMBIS: if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(unsigned int))) == 0) { Get_user(ival, (unsigned int *) arg); rio_setsignals(port, ((ival & TIOCM_DTR) ? 1 : -1), ((ival & TIOCM_RTS) ? 1 : -1)); } break; case TIOCMBIC: if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(unsigned int))) == 0) { Get_user(ival, (unsigned int *) arg); rio_setsignals(port, ((ival & TIOCM_DTR) ? 0 : -1), ((ival & TIOCM_RTS) ? 0 : -1)); } break; case TIOCMSET: if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(unsigned int))) == 0) { Get_user(ival, (unsigned int *) arg); rio_setsignals(port, ((ival & TIOCM_DTR) ? 1 : 0), ((ival & TIOCM_RTS) ? 1 : 0)); } break;#endif 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. * * ********************************************************************** */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 int rio_init_drivers(void){ int error; func_enter(); memset(&rio_driver, 0, sizeof(rio_driver)); rio_driver.magic = TTY_DRIVER_MAGIC; rio_driver.driver_name = "specialix_rio"; rio_driver.name = "ttySR"; rio_driver.major = RIO_NORMAL_MAJOR0; rio_driver.num = 256; rio_driver.type = TTY_DRIVER_TYPE_SERIAL; rio_driver.subtype = RIO_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; rio_driver.refcount = &rio_refcount; rio_driver.table = rio_table; rio_driver.termios = rio_termios; rio_driver.termios_locked = rio_termios_locked; rio_driver.open = riotopen; rio_driver.close = gs_close; rio_driver.write = gs_write; rio_driver.put_char = gs_put_char; rio_driver.flush_chars = gs_flush_chars; rio_driver.write_room = gs_write_room; rio_driver.chars_in_buffer = gs_chars_in_buffer; rio_driver.flush_buffer = gs_flush_buffer; rio_driver.ioctl = rio_ioctl; rio_driver.throttle = rio_throttle; rio_driver.unthrottle = rio_unthrottle; rio_driver.set_termios = gs_set_termios; rio_driver.stop = gs_stop; rio_driver.start = gs_start; rio_driver.hangup = gs_hangup; rio_driver2 = rio_driver; rio_driver.major = RIO_NORMAL_MAJOR1; rio_callout_driver = rio_driver; rio_callout_driver.name = "cusr"; rio_callout_driver.major = RIO_CALLOUT_MAJOR0; rio_callout_driver.subtype = RIO_TYPE_CALLOUT; rio_callout_driver2 = rio_callout_driver; rio_callout_driver2.major = RIO_CALLOUT_MAJOR1; rio_dprintk (RIO_DEBUG_INIT, "set_termios = %p\n", gs_set_termios); if ((error = tty_register_driver(&rio_driver))) goto bad1; if ((error = tty_register_driver(&rio_driver2))) goto bad2; if ((error = tty_register_driver(&rio_callout_driver))) goto bad3; if ((error = tty_register_driver(&rio_callout_driver2))) goto bad4; func_exit(); return 0; /* bad5:tty_unregister_driver (&rio_callout_driver2); */ bad4:tty_unregister_driver (&rio_callout_driver); bad3:tty_unregister_driver (&rio_driver2); bad2:tty_unregister_driver (&rio_driver); bad1: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); if (p) memset(p, 0, size); return p;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -