📄 cypress_m8.c
字号:
usb_clear_halt(serial->dev, 0x81); usb_clear_halt(serial->dev, 0x02); spin_lock_irqsave(&priv->lock, flags); /* reset read/write statistics */ priv->bytes_in = 0; priv->bytes_out = 0; priv->cmd_count = 0; priv->rx_flags = 0; spin_unlock_irqrestore(&priv->lock, flags); /* setting to zero could cause data loss */ port->tty->low_latency = 1; /* raise both lines and set termios */ spin_lock_irqsave(&priv->lock, flags); priv->line_control = CONTROL_DTR | CONTROL_RTS; priv->cmd_ctrl = 1; spin_unlock_irqrestore(&priv->lock, flags); result = cypress_write(port, NULL, 0); if (result) { dev_err(&port->dev, "%s - failed setting the control lines - error %d\n", __FUNCTION__, result); return result; } else dbg("%s - success setting the control lines", __FUNCTION__); cypress_set_termios(port, &priv->tmp_termios); /* setup the port and start reading from the device */ if(!port->interrupt_in_urb){ err("%s - interrupt_in_urb is empty!", __FUNCTION__); return(-1); } usb_fill_int_urb(port->interrupt_in_urb, serial->dev, usb_rcvintpipe(serial->dev, port->interrupt_in_endpointAddress), port->interrupt_in_urb->transfer_buffer, port->interrupt_in_urb->transfer_buffer_length, cypress_read_int_callback, port, interval); result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL); if (result){ dev_err(&port->dev, "%s - failed submitting read urb, error %d\n", __FUNCTION__, result); } return result;} /* cypress_open */static void cypress_close(struct usb_serial_port *port, struct file * filp){ struct cypress_private *priv = usb_get_serial_port_data(port); unsigned int c_cflag; unsigned long flags; int bps; long timeout; wait_queue_t wait; dbg("%s - port %d", __FUNCTION__, port->number); /* wait for data to drain from buffer */ spin_lock_irqsave(&priv->lock, flags); timeout = CYPRESS_CLOSING_WAIT; init_waitqueue_entry(&wait, current); add_wait_queue(&port->tty->write_wait, &wait); for (;;) { set_current_state(TASK_INTERRUPTIBLE); if (cypress_buf_data_avail(priv->buf) == 0 || timeout == 0 || signal_pending(current) || !usb_get_intfdata(port->serial->interface)) 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); /* clear out any remaining data in the buffer */ cypress_buf_clear(priv->buf); spin_unlock_irqrestore(&priv->lock, flags); /* wait for characters to drain from device */ 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 - stopping urbs", __FUNCTION__); usb_kill_urb (port->interrupt_in_urb); usb_kill_urb (port->interrupt_out_urb); if (port->tty) { c_cflag = port->tty->termios->c_cflag; if (c_cflag & HUPCL) { /* drop dtr and rts */ priv = usb_get_serial_port_data(port); spin_lock_irqsave(&priv->lock, flags); priv->line_control = 0; priv->cmd_ctrl = 1; spin_unlock_irqrestore(&priv->lock, flags); cypress_write(port, NULL, 0); } } if (stats) dev_info (&port->dev, "Statistics: %d Bytes In | %d Bytes Out | %d Commands Issued\n", priv->bytes_in, priv->bytes_out, priv->cmd_count);} /* cypress_close */static int cypress_write(struct usb_serial_port *port, const unsigned char *buf, int count){ struct cypress_private *priv = usb_get_serial_port_data(port); unsigned long flags; dbg("%s - port %d, %d bytes", __FUNCTION__, port->number, count); /* line control commands, which need to be executed immediately, are not put into the buffer for obvious reasons. */ if (priv->cmd_ctrl) { count = 0; goto finish; } if (!count) return count; spin_lock_irqsave(&priv->lock, flags); count = cypress_buf_put(priv->buf, buf, count); spin_unlock_irqrestore(&priv->lock, flags);finish: cypress_send(port); return count;} /* cypress_write */static void cypress_send(struct usb_serial_port *port){ int count = 0, result, offset, actual_size; struct cypress_private *priv = usb_get_serial_port_data(port); unsigned long flags; dbg("%s - port %d", __FUNCTION__, port->number); dbg("%s - interrupt out size is %d", __FUNCTION__, port->interrupt_out_size); spin_lock_irqsave(&priv->lock, flags); if (priv->write_urb_in_use) { dbg("%s - can't write, urb in use", __FUNCTION__); spin_unlock_irqrestore(&priv->lock, flags); return; } spin_unlock_irqrestore(&priv->lock, flags); /* clear buffer */ memset(port->interrupt_out_urb->transfer_buffer, 0, port->interrupt_out_size); spin_lock_irqsave(&priv->lock, flags); switch (port->interrupt_out_size) { case 32: /* this is for the CY7C64013... */ offset = 2; port->interrupt_out_buffer[0] = priv->line_control; break; case 8: /* this is for the CY7C63743... */ offset = 1; port->interrupt_out_buffer[0] = priv->line_control; break; default: dbg("%s - wrong packet size", __FUNCTION__); spin_unlock_irqrestore(&priv->lock, flags); return; } if (priv->line_control & CONTROL_RESET) priv->line_control &= ~CONTROL_RESET; if (priv->cmd_ctrl) { priv->cmd_count++; dbg("%s - line control command being issued", __FUNCTION__); spin_unlock_irqrestore(&priv->lock, flags); goto send; } else spin_unlock_irqrestore(&priv->lock, flags); count = cypress_buf_get(priv->buf, &port->interrupt_out_buffer[offset], port->interrupt_out_size-offset); if (count == 0) { return; } switch (port->interrupt_out_size) { case 32: port->interrupt_out_buffer[1] = count; break; case 8: port->interrupt_out_buffer[0] |= count; } dbg("%s - count is %d", __FUNCTION__, count);send: spin_lock_irqsave(&priv->lock, flags); priv->write_urb_in_use = 1; spin_unlock_irqrestore(&priv->lock, flags); if (priv->cmd_ctrl) actual_size = 1; else actual_size = count + (port->interrupt_out_size == 32 ? 2 : 1); usb_serial_debug_data(debug, &port->dev, __FUNCTION__, port->interrupt_out_size, port->interrupt_out_urb->transfer_buffer); port->interrupt_out_urb->transfer_buffer_length = actual_size; port->interrupt_out_urb->dev = port->serial->dev; port->interrupt_out_urb->interval = interval; result = usb_submit_urb (port->interrupt_out_urb, GFP_ATOMIC); if (result) { dev_err(&port->dev, "%s - failed submitting write urb, error %d\n", __FUNCTION__, result); priv->write_urb_in_use = 0; } spin_lock_irqsave(&priv->lock, flags); if (priv->cmd_ctrl) { priv->cmd_ctrl = 0; } priv->bytes_out += count; /* do not count the line control and size bytes */ spin_unlock_irqrestore(&priv->lock, flags); schedule_work(&port->work);} /* cypress_send *//* returns how much space is available in the soft buffer */static int cypress_write_room(struct usb_serial_port *port){ struct cypress_private *priv = usb_get_serial_port_data(port); int room = 0; unsigned long flags; dbg("%s - port %d", __FUNCTION__, port->number); spin_lock_irqsave(&priv->lock, flags); room = cypress_buf_space_avail(priv->buf); spin_unlock_irqrestore(&priv->lock, flags); dbg("%s - returns %d", __FUNCTION__, room); return room;}static int cypress_tiocmget (struct usb_serial_port *port, struct file *file){ struct cypress_private *priv = usb_get_serial_port_data(port); __u8 status, control; unsigned int result = 0; unsigned long flags; dbg("%s - port %d", __FUNCTION__, port->number); spin_lock_irqsave(&priv->lock, flags); control = priv->line_control; status = priv->current_status; spin_unlock_irqrestore(&priv->lock, flags); result = ((control & CONTROL_DTR) ? TIOCM_DTR : 0) | ((control & CONTROL_RTS) ? TIOCM_RTS : 0) | ((status & UART_CTS) ? TIOCM_CTS : 0) | ((status & UART_DSR) ? TIOCM_DSR : 0) | ((status & UART_RI) ? TIOCM_RI : 0) | ((status & UART_CD) ? TIOCM_CD : 0); dbg("%s - result = %x", __FUNCTION__, result); return result;}static int cypress_tiocmset (struct usb_serial_port *port, struct file *file, unsigned int set, unsigned int clear){ struct cypress_private *priv = usb_get_serial_port_data(port); unsigned long flags; dbg("%s - port %d", __FUNCTION__, port->number); spin_lock_irqsave(&priv->lock, flags); if (set & TIOCM_RTS) priv->line_control |= CONTROL_RTS; if (set & TIOCM_DTR) priv->line_control |= CONTROL_DTR; if (clear & TIOCM_RTS) priv->line_control &= ~CONTROL_RTS; if (clear & TIOCM_DTR) priv->line_control &= ~CONTROL_DTR; spin_unlock_irqrestore(&priv->lock, flags); priv->cmd_ctrl = 1; return cypress_write(port, NULL, 0);}static int cypress_ioctl (struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg){ struct cypress_private *priv = usb_get_serial_port_data(port); dbg("%s - port %d, cmd 0x%.4x", __FUNCTION__, port->number, cmd); switch (cmd) { case TIOCGSERIAL: if (copy_to_user((void __user *)arg, port->tty->termios, sizeof(struct termios))) { return -EFAULT; } return (0); break; case TIOCSSERIAL: if (copy_from_user(port->tty->termios, (void __user *)arg, sizeof(struct termios))) { return -EFAULT; } /* here we need to call cypress_set_termios to invoke the new settings */ cypress_set_termios(port, &priv->tmp_termios); return (0); break; /* these are called when setting baud rate from gpsd */ case TCGETS: if (copy_to_user((void __user *)arg, port->tty->termios, sizeof(struct termios))) { return -EFAULT; } return (0); break; case TCSETS: if (copy_from_user(port->tty->termios, (void __user *)arg, sizeof(struct termios))) { return -EFAULT; } /* here we need to call cypress_set_termios to invoke the new settings */ cypress_set_termios(port, &priv->tmp_termios); return (0); break; /* This code comes from drivers/char/serial.c and ftdi_sio.c */ case TIOCMIWAIT: while (priv != NULL) { interruptible_sleep_on(&priv->delta_msr_wait); /* see if a signal did it */ if (signal_pending(current)) return -ERESTARTSYS; else { char diff = priv->diff_status; if (diff == 0) { return -EIO; /* no change => error */ } /* consume all events */ priv->diff_status = 0; /* return 0 if caller wanted to know about these bits */ if ( ((arg & TIOCM_RNG) && (diff & UART_RI)) || ((arg & TIOCM_DSR) && (diff & UART_DSR)) || ((arg & TIOCM_CD) && (diff & UART_CD)) || ((arg & TIOCM_CTS) && (diff & UART_CTS)) ) { return 0; } /* otherwise caller can't care less about what happened, * and so we continue to wait for more events. */ } } return 0; break; default: break; } dbg("%s - arg not supported - it was 0x%04x - check include/asm/ioctls.h", __FUNCTION__, cmd); return -ENOIOCTLCMD;} /* cypress_ioctl */static void cypress_set_termios (struct usb_serial_port *port, struct termios *old_termios){ struct cypress_private *priv = usb_get_serial_port_data(port); struct tty_struct *tty; int data_bits, stop_bits, parity_type, parity_enable; unsigned cflag, iflag, baud_mask; unsigned long flags; __u8 oldlines; int linechange = 0; dbg("%s - port %d", __FUNCTION__, port->number); tty = port->tty; if ((!tty) || (!tty->termios)) { dbg("%s - no tty structures", __FUNCTION__); return; } spin_lock_irqsave(&priv->lock, flags); if (!priv->termios_initialized) { if (priv->chiptype == CT_EARTHMATE) { *(tty->termios) = tty_std_termios; tty->termios->c_cflag = B4800 | CS8 | CREAD | HUPCL | CLOCAL; } else if (priv->chiptype == CT_CYPHIDCOM) { *(tty->termios) = tty_std_termios; tty->termios->c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; } priv->termios_initialized = 1; } spin_unlock_irqrestore(&priv->lock, flags); cflag = tty->termios->c_cflag; iflag = tty->termios->c_iflag; /* check if there are new settings */ if (old_termios) { if ((cflag != old_termios->c_cflag) || (RELEVANT_IFLAG(iflag) != RELEVANT_IFLAG(old_termios->c_iflag))) { dbg("%s - attempting to set new termios settings", __FUNCTION__); /* should make a copy of this in case something goes * wrong in the function, we can restore it */ spin_lock_irqsave(&priv->lock, flags); priv->tmp_termios = *(tty->termios); spin_unlock_irqrestore(&priv->lock, flags); } else { dbg("%s - nothing to do, exiting", __FUNCTION__); return; } } else return; /* set number of data bits, parity, stop bits */ /* when parity is disabled the parity type bit is ignored */ /* 1 means 2 stop bits, 0 means 1 stop bit */ stop_bits = cflag & CSTOPB ? 1 : 0; if (cflag & PARENB) { parity_enable = 1; /* 1 means odd parity, 0 means even parity */ parity_type = cflag & PARODD ? 1 : 0; } else parity_enable = parity_type = 0; if (cflag & CSIZE) { switch (cflag & CSIZE) { case CS5: data_bits = 0; break; case CS6: data_bits = 1; break; case CS7: data_bits = 2; break; case CS8: data_bits = 3; break; default: err("%s - CSIZE was set, but not CS5-CS8", __FUNCTION__); data_bits = 3; } } else data_bits = 3; spin_lock_irqsave(&priv->lock, flags); oldlines = priv->line_control; if ((cflag & CBAUD) == B0) { /* drop dtr and rts */ dbg("%s - dropping the lines, baud rate 0bps", __FUNCTION__); baud_mask = B0; priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS); } else { baud_mask = (cflag & CBAUD); switch(baud_mask) { case B300: dbg("%s - setting baud 300bps", __FUNCTION__); break; case B600: dbg("%s - setting baud 600bps", __FUNCTION__); break; case B1200: dbg("%s - setting baud 1200bps", __FUNCTION__); break; case B2400: dbg("%s - setting baud 2400bps", __FUNCTION__); break; case B4800: dbg("%s - setting baud 4800bps", __FUNCTION__); break; case B9600: dbg("%s - setting baud 9600bps", __FUNCTION__); break; case B19200: dbg("%s - setting baud 19200bps", __FUNCTION__); break; case B38400: dbg("%s - setting baud 38400bps", __FUNCTION__); break; case B57600: dbg("%s - setting baud 57600bps", __FUNCTION__); break; case B115200: dbg("%s - setting baud 115200bps", __FUNCTION__); break; default: dbg("%s - unknown masked baud rate", __FUNCTION__); } priv->line_control = (CONTROL_DTR | CONTROL_RTS); } spin_unlock_irqrestore(&priv->lock, flags); dbg("%s - sending %d stop_bits, %d parity_enable, %d parity_type, " "%d data_bits (+5)", __FUNCTION__, stop_bits, parity_enable, parity_type, data_bits);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -