📄 rio_linux.c
字号:
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;#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; 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) {#if 0 case TIOCGSOFTCAR: rc = put_user(((tty->termios->c_cflag & CLOCAL) ? 1 : 0), (unsigned int *) arg); break;#endif 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: 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 /* * note: these IOCTLs no longer reach here. Use * tiocmset/tiocmget driver methods instead. The * #if 0 disablement predates this comment. */ 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 = get_user(ival, (unsigned int *) arg)) == 0) { rio_setsignals(port, ((ival & TIOCM_DTR) ? 1 : -1), ((ival & TIOCM_RTS) ? 1 : -1)); } break; case TIOCMBIC: if ((rc = get_user(ival, (unsigned int *) arg)) == 0) { rio_setsignals(port, ((ival & TIOCM_DTR) ? 0 : -1), ((ival & TIOCM_RTS) ? 0 : -1)); } break; case TIOCMSET: if ((rc = get_user(ival, (unsigned int *) arg)) == 0) { 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. * * ********************************************************************** */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)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -