📄 oti6858.c
字号:
chars = pl2303_buf_data_avail(priv->buf); spin_unlock_irqrestore(&priv->lock, flags); return chars;}static void oti6858_set_termios(struct usb_serial_port *port, struct ktermios *old_termios){ struct oti6858_private *priv = usb_get_serial_port_data(port); unsigned long flags; unsigned int cflag; u8 frame_fmt, control; u16 divisor; int br; dbg("%s(port = %d)", __FUNCTION__, port->number); if ((!port->tty) || (!port->tty->termios)) { dbg("%s(): no tty structures", __FUNCTION__); return; } spin_lock_irqsave(&priv->lock, flags); if (!priv->flags.termios_initialized) { *(port->tty->termios) = tty_std_termios; port->tty->termios->c_cflag = B38400 | CS8 | CREAD | HUPCL | CLOCAL; priv->flags.termios_initialized = 1; } spin_unlock_irqrestore(&priv->lock, flags); cflag = port->tty->termios->c_cflag; spin_lock_irqsave(&priv->lock, flags); divisor = priv->pending_setup.divisor; frame_fmt = priv->pending_setup.frame_fmt; control = priv->pending_setup.control; spin_unlock_irqrestore(&priv->lock, flags); frame_fmt &= ~FMT_DATA_BITS_MASK; switch (cflag & CSIZE) { case CS5: frame_fmt |= FMT_DATA_BITS_5; break; case CS6: frame_fmt |= FMT_DATA_BITS_6; break; case CS7: frame_fmt |= FMT_DATA_BITS_7; break; default: case CS8: frame_fmt |= FMT_DATA_BITS_8; break; } /* manufacturer claims that this device can work with baud rates * up to 3 Mbps; I've tested it only on 115200 bps, so I can't * guarantee that any other baud rate will work (especially * the higher ones) */ br = tty_get_baud_rate(port->tty); if (br == 0) { divisor = 0; } else if (br <= OTI6858_MAX_BAUD_RATE) { int real_br; divisor = (96000000 + 8 * br) / (16 * br); real_br = 96000000 / (16 * divisor); if ((((real_br - br) * 100 + br - 1) / br) > 2) { dbg("%s(): baud rate %d is invalid", __FUNCTION__, br); return; } divisor = cpu_to_le16(divisor); } else { dbg("%s(): baud rate %d is too high", __FUNCTION__, br); return; } frame_fmt &= ~FMT_STOP_BITS_MASK; if ((cflag & CSTOPB) != 0) { frame_fmt |= FMT_STOP_BITS_2; } else { frame_fmt |= FMT_STOP_BITS_1; } frame_fmt &= ~FMT_PARITY_MASK; if ((cflag & PARENB) != 0) { if ((cflag & PARODD) != 0) { frame_fmt |= FMT_PARITY_ODD; } else { frame_fmt |= FMT_PARITY_EVEN; } } else { frame_fmt |= FMT_PARITY_NONE; } control &= ~CONTROL_MASK; if ((cflag & CRTSCTS) != 0) control |= (CONTROL_DTR_HIGH | CONTROL_RTS_HIGH); /* change control lines if we are switching to or from B0 */ /* FIXME: spin_lock_irqsave(&priv->lock, flags); control = priv->line_control; if ((cflag & CBAUD) == B0) priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS); else priv->line_control |= (CONTROL_DTR | CONTROL_RTS); if (control != priv->line_control) { control = priv->line_control; spin_unlock_irqrestore(&priv->lock, flags); set_control_lines(serial->dev, control); } else { spin_unlock_irqrestore(&priv->lock, flags); } */ spin_lock_irqsave(&priv->lock, flags); if (divisor != priv->pending_setup.divisor || control != priv->pending_setup.control || frame_fmt != priv->pending_setup.frame_fmt) { priv->pending_setup.divisor = divisor; priv->pending_setup.control = control; priv->pending_setup.frame_fmt = frame_fmt; } spin_unlock_irqrestore(&priv->lock, flags);}static int oti6858_open(struct usb_serial_port *port, struct file *filp){ struct oti6858_private *priv = usb_get_serial_port_data(port); struct ktermios tmp_termios; struct usb_serial *serial = port->serial; struct oti6858_control_pkt *buf; unsigned long flags; int result; dbg("%s(port = %d)", __FUNCTION__, port->number); usb_clear_halt(serial->dev, port->write_urb->pipe); usb_clear_halt(serial->dev, port->read_urb->pipe); if (port->open_count != 1) return 0; if ((buf = kmalloc(OTI6858_CTRL_PKT_SIZE, GFP_KERNEL)) == NULL) { dev_err(&port->dev, "%s(): out of memory!\n", __FUNCTION__); return -ENOMEM; } result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0), OTI6858_REQ_T_GET_STATUS, OTI6858_REQ_GET_STATUS, 0, 0, buf, OTI6858_CTRL_PKT_SIZE, 100); if (result != OTI6858_CTRL_PKT_SIZE) { /* assume default (after power-on reset) values */ buf->divisor = cpu_to_le16(0x009c); /* 38400 bps */ buf->frame_fmt = 0x03; /* 8N1 */ buf->something = 0x43; buf->control = 0x4c; /* DTR, RTS */ buf->tx_status = 0x00; buf->pin_state = 0x5b; /* RTS, CTS, DSR, DTR, RI, DCD */ buf->rx_bytes_avail = 0x00; } spin_lock_irqsave(&priv->lock, flags); memcpy(&priv->status, buf, OTI6858_CTRL_PKT_SIZE); priv->pending_setup.divisor = buf->divisor; priv->pending_setup.frame_fmt = buf->frame_fmt; priv->pending_setup.control = buf->control; spin_unlock_irqrestore(&priv->lock, flags); kfree(buf); dbg("%s(): submitting interrupt urb", __FUNCTION__); port->interrupt_in_urb->dev = serial->dev; result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); if (result != 0) { dev_err(&port->dev, "%s(): usb_submit_urb() failed" " with error %d\n", __FUNCTION__, result); oti6858_close(port, NULL); return -EPROTO; } /* setup termios */ if (port->tty) oti6858_set_termios(port, &tmp_termios); return 0;}static void oti6858_close(struct usb_serial_port *port, struct file *filp){ struct oti6858_private *priv = usb_get_serial_port_data(port); unsigned long flags; long timeout; wait_queue_t wait; dbg("%s(port = %d)", __FUNCTION__, port->number); /* wait for data to drain from the buffer */ spin_lock_irqsave(&priv->lock, flags); timeout = 30 * HZ; /* PL2303_CLOSING_WAIT */ init_waitqueue_entry(&wait, current); add_wait_queue(&port->tty->write_wait, &wait); dbg("%s(): entering wait loop", __FUNCTION__); for (;;) { set_current_state(TASK_INTERRUPTIBLE); if (pl2303_buf_data_avail(priv->buf) == 0 || timeout == 0 || signal_pending(current) || !usb_get_intfdata(port->serial->interface)) /* disconnect */ break; spin_unlock_irqrestore(&priv->lock, flags); timeout = schedule_timeout(timeout); spin_lock_irqsave(&priv->lock, flags); } set_current_state(TASK_RUNNING); remove_wait_queue(&port->tty->write_wait, &wait); dbg("%s(): after wait loop", __FUNCTION__); /* clear out any remaining data in the buffer */ pl2303_buf_clear(priv->buf); spin_unlock_irqrestore(&priv->lock, flags); /* wait for characters to drain from the device */ /* (this is long enough for the entire 256 byte */ /* pl2303 hardware buffer to drain with no flow */ /* control for data rates of 1200 bps or more, */ /* for lower rates we should really know how much */ /* data is in the buffer to compute a delay */ /* that is not unnecessarily long) */ /* FIXME bps = tty_get_baud_rate(port->tty); if (bps > 1200) timeout = max((HZ*2560)/bps,HZ/10); else */ timeout = 2*HZ; schedule_timeout_interruptible(timeout); dbg("%s(): after schedule_timeout_interruptible()", __FUNCTION__); /* cancel scheduled setup */ cancel_delayed_work(&priv->delayed_setup_work); cancel_delayed_work(&priv->delayed_write_work); flush_scheduled_work(); /* shutdown our urbs */ dbg("%s(): shutting down urbs", __FUNCTION__); usb_kill_urb(port->write_urb); usb_kill_urb(port->read_urb); usb_kill_urb(port->interrupt_in_urb); /* if (port->tty && (port->tty->termios->c_cflag) & HUPCL) { // drop DTR and RTS spin_lock_irqsave(&priv->lock, flags); priv->pending_setup.control &= ~CONTROL_MASK; spin_unlock_irqrestore(&priv->lock, flags); } */}static int oti6858_tiocmset(struct usb_serial_port *port, struct file *file, unsigned int set, unsigned int clear){ struct oti6858_private *priv = usb_get_serial_port_data(port); unsigned long flags; u8 control; dbg("%s(port = %d, set = 0x%08x, clear = 0x%08x)", __FUNCTION__, port->number, set, clear); if (!usb_get_intfdata(port->serial->interface)) return -ENODEV; /* FIXME: check if this is correct (active high/low) */ spin_lock_irqsave(&priv->lock, flags); control = priv->pending_setup.control; if ((set & TIOCM_RTS) != 0) control |= CONTROL_RTS_HIGH; if ((set & TIOCM_DTR) != 0) control |= CONTROL_DTR_HIGH; if ((clear & TIOCM_RTS) != 0) control &= ~CONTROL_RTS_HIGH; if ((clear & TIOCM_DTR) != 0) control &= ~CONTROL_DTR_HIGH; if (control != priv->pending_setup.control) { priv->pending_setup.control = control; } spin_unlock_irqrestore(&priv->lock, flags); return 0;}static int oti6858_tiocmget(struct usb_serial_port *port, struct file *file){ struct oti6858_private *priv = usb_get_serial_port_data(port); unsigned long flags; unsigned pin_state; unsigned result = 0; dbg("%s(port = %d)", __FUNCTION__, port->number); if (!usb_get_intfdata(port->serial->interface)) return -ENODEV; spin_lock_irqsave(&priv->lock, flags); pin_state = priv->status.pin_state & PIN_MASK; spin_unlock_irqrestore(&priv->lock, flags); /* FIXME: check if this is correct (active high/low) */ if ((pin_state & PIN_RTS) != 0) result |= TIOCM_RTS; if ((pin_state & PIN_CTS) != 0) result |= TIOCM_CTS; if ((pin_state & PIN_DSR) != 0) result |= TIOCM_DSR; if ((pin_state & PIN_DTR) != 0) result |= TIOCM_DTR; if ((pin_state & PIN_RI) != 0) result |= TIOCM_RI; if ((pin_state & PIN_DCD) != 0) result |= TIOCM_CD; dbg("%s() = 0x%08x", __FUNCTION__, result); return result;}static int wait_modem_info(struct usb_serial_port *port, unsigned int arg){ struct oti6858_private *priv = usb_get_serial_port_data(port); unsigned long flags; unsigned int prev, status; unsigned int changed; spin_lock_irqsave(&priv->lock, flags); prev = priv->status.pin_state; spin_unlock_irqrestore(&priv->lock, flags); while (1) { wait_event_interruptible(priv->intr_wait, priv->status.pin_state != prev); if (signal_pending(current)) return -ERESTARTSYS; spin_lock_irqsave(&priv->lock, flags); status = priv->status.pin_state & PIN_MASK; spin_unlock_irqrestore(&priv->lock, flags); changed = prev ^ status; /* FIXME: check if this is correct (active high/low) */ if ( ((arg & TIOCM_RNG) && (changed & PIN_RI)) || ((arg & TIOCM_DSR) && (changed & PIN_DSR)) || ((arg & TIOCM_CD) && (changed & PIN_DCD)) || ((arg & TIOCM_CTS) && (changed & PIN_CTS))) { return 0; } prev = status; } /* NOTREACHED */ return 0;}static int oti6858_ioctl(struct usb_serial_port *port, struct file *file, unsigned int cmd, unsigned long arg){ void __user *user_arg = (void __user *) arg; unsigned int x; dbg("%s(port = %d, cmd = 0x%04x, arg = 0x%08lx)", __FUNCTION__, port->number, cmd, arg); switch (cmd) { case TCFLSH: /* FIXME */ return 0; case TIOCMBIS: if (copy_from_user(&x, user_arg, sizeof(x))) return -EFAULT; return oti6858_tiocmset(port, NULL, x, 0); case TIOCMBIC: if (copy_from_user(&x, user_arg, sizeof(x))) return -EFAULT; return oti6858_tiocmset(port, NULL, 0, x); case TIOCGSERIAL: if (copy_to_user(user_arg, port->tty->termios, sizeof(struct ktermios))) { return -EFAULT; } return 0; case TIOCSSERIAL: if (copy_from_user(port->tty->termios, user_arg, sizeof(struct ktermios))) { return -EFAULT; } oti6858_set_termios(port, NULL); return 0; case TIOCMIWAIT: dbg("%s(): TIOCMIWAIT", __FUNCTION__); return wait_modem_info(port, arg); default: dbg("%s(): 0x%04x not supported", __FUNCTION__, cmd); break; } return -ENOIOCTLCMD;}static void oti6858_break_ctl(struct usb_serial_port *port, int break_state){ int state; dbg("%s(port = %d)", __FUNCTION__, port->number); state = (break_state == 0) ? 0 : 1; dbg("%s(): turning break %s", __FUNCTION__, state ? "on" : "off"); /* FIXME *//* result = usb_control_msg (serial->dev, usb_sndctrlpipe (serial->dev, 0), BREAK_REQUEST, BREAK_REQUEST_TYPE, state, 0, NULL, 0, 100); if (result != 0) dbg("%s(): error sending break", __FUNCTION__); */}static void oti6858_shutdown(struct usb_serial *serial){ struct oti6858_private *priv; int i;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -