📄 cypress_m8.c
字号:
cypress_serial_control(port, baud_mask, data_bits, stop_bits, parity_enable, parity_type, 0, CYPRESS_SET_CONFIG); /* we perform a CYPRESS_GET_CONFIG so that the current settings are * filled into the private structure this should confirm that all is * working if it returns what we just set */ cypress_serial_control(port, 0, 0, 0, 0, 0, 0, CYPRESS_GET_CONFIG); /* Here we can define custom tty settings for devices; the main tty * termios flag base comes from empeg.c */ spin_lock_irqsave(&priv->lock, flags); if ( (priv->chiptype == CT_EARTHMATE) && (priv->baud_rate == 4800) ) { dbg("Using custom termios settings for a baud rate of " "4800bps."); /* define custom termios settings for NMEA protocol */ tty->termios->c_iflag /* input modes - */ &= ~(IGNBRK /* disable ignore break */ | BRKINT /* disable break causes interrupt */ | PARMRK /* disable mark parity errors */ | ISTRIP /* disable clear high bit of input char */ | INLCR /* disable translate NL to CR */ | IGNCR /* disable ignore CR */ | ICRNL /* disable translate CR to NL */ | IXON); /* disable enable XON/XOFF flow control */ tty->termios->c_oflag /* output modes */ &= ~OPOST; /* disable postprocess output char */ tty->termios->c_lflag /* line discipline modes */ &= ~(ECHO /* disable echo input characters */ | ECHONL /* disable echo new line */ | ICANON /* disable erase, kill, werase, and rprnt special characters */ | ISIG /* disable interrupt, quit, and suspend special characters */ | IEXTEN); /* disable non-POSIX special characters */ } /* CT_CYPHIDCOM: Application should handle this for device */ linechange = (priv->line_control != oldlines); spin_unlock_irqrestore(&priv->lock, flags); /* if necessary, set lines */ if (linechange) { priv->cmd_ctrl = 1; cypress_write(port, NULL, 0); }} /* cypress_set_termios *//* returns amount of data still left in soft buffer */static int cypress_chars_in_buffer(struct usb_serial_port *port){ struct cypress_private *priv = usb_get_serial_port_data(port); int chars = 0; unsigned long flags; dbg("%s - port %d", __FUNCTION__, port->number); spin_lock_irqsave(&priv->lock, flags); chars = cypress_buf_data_avail(priv->buf); spin_unlock_irqrestore(&priv->lock, flags); dbg("%s - returns %d", __FUNCTION__, chars); return chars;}static void cypress_throttle (struct usb_serial_port *port){ 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); priv->rx_flags = THROTTLED; spin_unlock_irqrestore(&priv->lock, flags);}static void cypress_unthrottle (struct usb_serial_port *port){ struct cypress_private *priv = usb_get_serial_port_data(port); int actually_throttled, result; unsigned long flags; dbg("%s - port %d", __FUNCTION__, port->number); spin_lock_irqsave(&priv->lock, flags); actually_throttled = priv->rx_flags & ACTUALLY_THROTTLED; priv->rx_flags = 0; spin_unlock_irqrestore(&priv->lock, flags); if (actually_throttled) { port->interrupt_in_urb->dev = port->serial->dev; result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC); if (result) dev_err(&port->dev, "%s - failed submitting read urb, " "error %d\n", __FUNCTION__, result); }}static void cypress_read_int_callback(struct urb *urb, struct pt_regs *regs){ struct usb_serial_port *port = (struct usb_serial_port *)urb->context; struct cypress_private *priv = usb_get_serial_port_data(port); struct tty_struct *tty; unsigned char *data = urb->transfer_buffer; unsigned long flags; char tty_flag = TTY_NORMAL; int havedata = 0; int bytes = 0; int result; int i = 0; dbg("%s - port %d", __FUNCTION__, port->number); if (urb->status) { dbg("%s - nonzero read status received: %d", __FUNCTION__, urb->status); return; } spin_lock_irqsave(&priv->lock, flags); if (priv->rx_flags & THROTTLED) { dbg("%s - now throttling", __FUNCTION__); priv->rx_flags |= ACTUALLY_THROTTLED; spin_unlock_irqrestore(&priv->lock, flags); return; } spin_unlock_irqrestore(&priv->lock, flags); tty = port->tty; if (!tty) { dbg("%s - bad tty pointer - exiting", __FUNCTION__); return; } spin_lock_irqsave(&priv->lock, flags); switch(urb->actual_length) { case 32: /* This is for the CY7C64013... */ priv->current_status = data[0] & 0xF8; bytes = data[1] + 2; i = 2; if (bytes > 2) havedata = 1; break; case 8: /* This is for the CY7C63743... */ priv->current_status = data[0] & 0xF8; bytes = (data[0] & 0x07) + 1; i = 1; if (bytes > 1) havedata = 1; break; default: dbg("%s - wrong packet size - received %d bytes", __FUNCTION__, urb->actual_length); spin_unlock_irqrestore(&priv->lock, flags); goto continue_read; } spin_unlock_irqrestore(&priv->lock, flags); usb_serial_debug_data (debug, &port->dev, __FUNCTION__, urb->actual_length, data); spin_lock_irqsave(&priv->lock, flags); /* check to see if status has changed */ if (priv != NULL) { if (priv->current_status != priv->prev_status) { priv->diff_status |= priv->current_status ^ priv->prev_status; wake_up_interruptible(&priv->delta_msr_wait); priv->prev_status = priv->current_status; } } spin_unlock_irqrestore(&priv->lock, flags); /* hangup, as defined in acm.c... this might be a bad place for it * though */ if (tty && !(tty->termios->c_cflag & CLOCAL) && !(priv->current_status & UART_CD)) { dbg("%s - calling hangup", __FUNCTION__); tty_hangup(tty); goto continue_read; } /* There is one error bit... I'm assuming it is a parity error * indicator as the generic firmware will set this bit to 1 if a * parity error occurs. * I can not find reference to any other error events. */ spin_lock_irqsave(&priv->lock, flags); if (priv->current_status & CYP_ERROR) { spin_unlock_irqrestore(&priv->lock, flags); tty_flag = TTY_PARITY; dbg("%s - Parity Error detected", __FUNCTION__); } else spin_unlock_irqrestore(&priv->lock, flags); /* process read if there is data other than line status */ if (tty && (bytes > i)) { for (; i < bytes ; ++i) { dbg("pushing byte number %d - %d - %c", i, data[i], data[i]); if(tty->flip.count >= TTY_FLIPBUF_SIZE) { tty_flip_buffer_push(tty); } tty_insert_flip_char(tty, data[i], tty_flag); } tty_flip_buffer_push(port->tty); } spin_lock_irqsave(&priv->lock, flags); /* control and status byte(s) are also counted */ priv->bytes_in += bytes; spin_unlock_irqrestore(&priv->lock, flags);continue_read: /* Continue trying to always read... unless the port has closed. */ if (port->open_count > 0) { usb_fill_int_urb(port->interrupt_in_urb, port->serial->dev, usb_rcvintpipe(port->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_ATOMIC); if (result) dev_err(&urb->dev->dev, "%s - failed resubmitting " "read urb, error %d\n", __FUNCTION__, result); } return;} /* cypress_read_int_callback */static void cypress_write_int_callback(struct urb *urb, struct pt_regs *regs){ struct usb_serial_port *port = (struct usb_serial_port *)urb->context; struct cypress_private *priv = usb_get_serial_port_data(port); int result; dbg("%s - port %d", __FUNCTION__, port->number); switch (urb->status) { case 0: /* success */ break; case -ECONNRESET: case -ENOENT: case -ESHUTDOWN: /* this urb is terminated, clean up */ dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status); priv->write_urb_in_use = 0; return; case -EPIPE: /* no break needed */ usb_clear_halt(port->serial->dev, 0x02); default: /* error in the urb, so we have to resubmit it */ dbg("%s - Overflow in write", __FUNCTION__); dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status); port->interrupt_out_urb->transfer_buffer_length = 1; port->interrupt_out_urb->dev = port->serial->dev; result = usb_submit_urb(port->interrupt_out_urb, GFP_ATOMIC); if (result) dev_err(&urb->dev->dev, "%s - failed resubmitting write urb, error %d\n", __FUNCTION__, result); else return; } priv->write_urb_in_use = 0; /* send any buffered data */ cypress_send(port);}/***************************************************************************** * Write buffer functions - buffering code from pl2303 used *****************************************************************************//* * cypress_buf_alloc * * Allocate a circular buffer and all associated memory. */static struct cypress_buf *cypress_buf_alloc(unsigned int size){ struct cypress_buf *cb; if (size == 0) return NULL; cb = (struct cypress_buf *)kmalloc(sizeof(struct cypress_buf), GFP_KERNEL); if (cb == NULL) return NULL; cb->buf_buf = kmalloc(size, GFP_KERNEL); if (cb->buf_buf == NULL) { kfree(cb); return NULL; } cb->buf_size = size; cb->buf_get = cb->buf_put = cb->buf_buf; return cb;}/* * cypress_buf_free * * Free the buffer and all associated memory. */static void cypress_buf_free(struct cypress_buf *cb){ if (cb) { kfree(cb->buf_buf); kfree(cb); }}/* * cypress_buf_clear * * Clear out all data in the circular buffer. */static void cypress_buf_clear(struct cypress_buf *cb){ if (cb != NULL) cb->buf_get = cb->buf_put; /* equivalent to a get of all data available */}/* * cypress_buf_data_avail * * Return the number of bytes of data available in the circular * buffer. */static unsigned int cypress_buf_data_avail(struct cypress_buf *cb){ if (cb != NULL) return ((cb->buf_size + cb->buf_put - cb->buf_get) % cb->buf_size); else return 0;}/* * cypress_buf_space_avail * * Return the number of bytes of space available in the circular * buffer. */static unsigned int cypress_buf_space_avail(struct cypress_buf *cb){ if (cb != NULL) return ((cb->buf_size + cb->buf_get - cb->buf_put - 1) % cb->buf_size); else return 0;}/* * cypress_buf_put * * Copy data data from a user buffer and put it into the circular buffer. * Restrict to the amount of space available. * * Return the number of bytes copied. */static unsigned int cypress_buf_put(struct cypress_buf *cb, const char *buf, unsigned int count){ unsigned int len; if (cb == NULL) return 0; len = cypress_buf_space_avail(cb); if (count > len) count = len; if (count == 0) return 0; len = cb->buf_buf + cb->buf_size - cb->buf_put; if (count > len) { memcpy(cb->buf_put, buf, len); memcpy(cb->buf_buf, buf+len, count - len); cb->buf_put = cb->buf_buf + count - len; } else { memcpy(cb->buf_put, buf, count); if (count < len) cb->buf_put += count; else /* count == len */ cb->buf_put = cb->buf_buf; } return count;}/* * cypress_buf_get * * Get data from the circular buffer and copy to the given buffer. * Restrict to the amount of data available. * * Return the number of bytes copied. */static unsigned int cypress_buf_get(struct cypress_buf *cb, char *buf, unsigned int count){ unsigned int len; if (cb == NULL) return 0; len = cypress_buf_data_avail(cb); if (count > len) count = len; if (count == 0) return 0; len = cb->buf_buf + cb->buf_size - cb->buf_get; if (count > len) { memcpy(buf, cb->buf_get, len); memcpy(buf+len, cb->buf_buf, count - len); cb->buf_get = cb->buf_buf + count - len; } else { memcpy(buf, cb->buf_get, count); if (count < len) cb->buf_get += count; else /* count == len */ cb->buf_get = cb->buf_buf; } return count;}/***************************************************************************** * Module functions *****************************************************************************/static int __init cypress_init(void){ int retval; dbg("%s", __FUNCTION__); retval = usb_serial_register(&cypress_earthmate_device); if (retval) goto failed_em_register; retval = usb_serial_register(&cypress_hidcom_device); if (retval) goto failed_hidcom_register; retval = usb_register(&cypress_driver); if (retval) goto failed_usb_register; info(DRIVER_DESC " " DRIVER_VERSION); return 0;failed_usb_register: usb_deregister(&cypress_driver);failed_hidcom_register: usb_serial_deregister(&cypress_hidcom_device);failed_em_register: usb_serial_deregister(&cypress_earthmate_device); return retval;}static void __exit cypress_exit (void){ dbg("%s", __FUNCTION__); usb_deregister (&cypress_driver); usb_serial_deregister (&cypress_earthmate_device); usb_serial_deregister (&cypress_hidcom_device);}module_init(cypress_init);module_exit(cypress_exit);MODULE_AUTHOR( DRIVER_AUTHOR );MODULE_DESCRIPTION( DRIVER_DESC );MODULE_VERSION( DRIVER_VERSION );MODULE_LICENSE("GPL");module_param(debug, bool, S_IRUGO | S_IWUSR);MODULE_PARM_DESC(debug, "Debug enabled or not");module_param(stats, bool, S_IRUGO | S_IWUSR);MODULE_PARM_DESC(stats, "Enable statistics or not");module_param(interval, int, S_IRUGO | S_IWUSR);MODULE_PARM_DESC(interval, "Overrides interrupt interval");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -