⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pl2303.c

📁 USB接口转换成RS232接口驱动程序
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
 * Prolific USB Serial Adapter Driver
 *
 *  Copyright (C) 2001
 *      Prolific Technology Inc.
 *
 *  This program is largely derived from work by the linux-usb group
 *  and associated source files.  Please see the usb/serial files for
 *  individual credits and copyrights.
 *
 */
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/signal.h>
#include <linux/errno.h>
#include <linux/poll.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/fcntl.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
#include <linux/tty_flip.h>
#include <linux/module.h>
#include <linux/spinlock.h>
#include <linux/usb.h>

#ifdef USB_SERIAL_DEBUG
static int  debug = 1;
#else
static int  debug;
#endif
#include "usb-serial.h"
#include "pl2303.h"

#define TRUE  1
#define FALSE 0

/* function prototypes for a Prolific USB Serial Adapter */
static int                                prolific_sa_startup(struct usb_serial *serial);
static void                               prolific_sa_shutdown(struct usb_serial *serial);
static int                                prolific_sa_open(struct usb_serial_port *port, struct file *filp);
static void                               prolific_sa_close(struct usb_serial_port *port, struct file *filp);
static void                               prolific_sa_read_int_callback(struct urb *urb);
static void                               prolific_sa_set_termios(struct usb_serial_port *port, struct termios *old);
static int                                prolific_sa_ioctl(struct usb_serial_port  *port, struct file             *file,
                                                            unsigned int            cmd, unsigned long           arg);
static void                               prolific_sa_break_ctl(struct usb_serial_port *port, int break_state);
static void                               prolific_set_dcr_state(struct usb_serial_port *port, int set);
static int							  prolific_sa_write(struct usb_serial_port *port, int from_user, const unsigned char *buf, int count);
static void							  prolific_sa_write_bulk_callback(struct urb *urb);

static __devinitdata struct usb_device_id id_table_combined[] = {
  { USB_DEVICE(PROLIFIC_SA_VID, PROLIFIC_SA_PID) },
  { } /* Terminating entry */
};

static __devinitdata struct usb_device_id prolific_sa_table[] = {
  { USB_DEVICE(PROLIFIC_SA_VID, PROLIFIC_SA_PID) },
  { } /* Terminating entry */
};

MODULE_DEVICE_TABLE(usb, id_table_combined);

/* All of the device info needed for the Prolific serial converter */
struct usb_serial_device_type prolific_sa_device =
{
name:
  "Prolific USB Serial Adapter",
  id_table : prolific_sa_table,                       /* the Prolific device */
  needs_interrupt_in : MUST_HAVE,                     /* this device must have an interrupt in endpoint */
  needs_bulk_in : MUST_HAVE,                          /* this device must have a bulk in endpoint */
  needs_bulk_out : MUST_HAVE,                         /* this device must have a bulk out endpoint */
  num_interrupt_in : 1,
  num_bulk_in : 1,
  num_bulk_out : 1,
  num_ports : 1,
  open : prolific_sa_open,
  close : prolific_sa_close,
  write : prolific_sa_write,
  read_int_callback : prolific_sa_read_int_callback,  /* How we get the status info */
  write_bulk_callback : prolific_sa_write_bulk_callback,
  ioctl : prolific_sa_ioctl,
  set_termios : prolific_sa_set_termios,
  break_ctl : prolific_sa_break_ctl,
  startup : prolific_sa_startup,
  shutdown : prolific_sa_shutdown,
};

struct line_coding {
  unsigned long dwDTERate;
  unsigned char bCharFormat;
  unsigned char bParityType;
  unsigned char bDatabits;
};

struct prolific_sa_private {
  unsigned long       control_state;
  unsigned char       last_lsr;
  unsigned char       last_msr;
  int                 bad_flow_control;
  struct line_coding  lineCoding;
  unsigned short      RTSDTRState;
};

/*
 * ***************************************************************************
 * Prolific USB Serial Adapter specific driver functions
 * ***************************************************************************
 */
#define WDR_TIMEOUT (HZ * 5)  /* default urb timeout */

/* assumes that struct usb_serial *serial is available */
#define BSA_USB_CMD(r, v) \
  usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), (r), PROLIFIC_SA_SET_REQUEST_CLASS_TYPE, (v), 0, NULL, 0, \
                  WDR_TIMEOUT)
#define BSA_USB_CMD_SET_DATA(r, v, data) \
  usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), (r), PROLIFIC_SA_SET_REQUEST_CLASS_TYPE, (v), 0, data, \
                  sizeof(data), WDR_TIMEOUT)
#define BSA_USB_CMD_SET_DATA_LEN(r, v, data, size) \
  usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), (r), PROLIFIC_SA_SET_REQUEST_CLASS_TYPE, (v), 0, data, \
                  size, WDR_TIMEOUT)
#define BSA_USB_CMD_SET_VENDOR(r, v, idx) \
  usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), (r), PROLIFIC_SA_SET_REQUEST_VENDOR_TYPE, (v), (idx), \
                  NULL, 0, WDR_TIMEOUT)
#define BSA_USB_CMD_GET_VENDOR_DATA(r, v, data, size) \
  usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0), (r), PROLIFIC_SA_GET_REQUEST_VENDOR_TYPE, (v), 0, data, \
                  size, WDR_TIMEOUT)

/* do some startup allocations not currently performed by usb_serial_probe() */
static int prolific_sa_startup(struct usb_serial *serial)
{
  struct usb_device           *dev = serial->dev;
  struct prolific_sa_private  *priv;

  /* allocate the private data structure */
  serial->port->private = kmalloc(sizeof(struct prolific_sa_private), GFP_KERNEL);
  if(!serial->port->private)
    return(-1); /* error */
  priv = (struct prolific_sa_private *)serial->port->private;

  /* set initial values for control structures */
  priv->control_state = 0;
  priv->last_lsr = 0;
  priv->last_msr = 0;

  /* see comments at top of file */
  priv->bad_flow_control = (dev->descriptor.bcdDevice <= 0x0206) ? 1 : 0;
  info("bcdDevice: %04x, bfc: %d", dev->descriptor.bcdDevice, priv->bad_flow_control);

  init_waitqueue_head(&serial->port->write_wait);

  return(0);
}

static void prolific_sa_shutdown(struct usb_serial *serial)
{
  int i;

  dbg(__FUNCTION__);

  /* stop reads and writes on all ports */
  for(i = 0; i < serial->num_ports; ++i) {
    while(serial->port[i].open_count > 0) {
      prolific_sa_close(&serial->port[i], NULL);
    }

    /* My special items, the standard routines free my urbs */
    if(serial->port[i].private)
      kfree(serial->port[i].private);
  }
}

static int prolific_sa_open(struct usb_serial_port *port, struct file *filp)
{
  unsigned long flags;

  dbg(__FUNCTION__ " port %d", port->number);

  spin_lock_irqsave(&port->port_lock, flags);

  ++port->open_count;
  MOD_INC_USE_COUNT;

  if(!port->active) {
    port->active = 1;

    /*Start reading from the device*/

    /* TODO: Look at possibility of submitting mulitple URBs to device to
		 *       enhance buffering.  Win trace shows 16 initial read URBs.
		 */
    port->read_urb->dev = port->serial->dev;
    if(usb_submit_urb(port->read_urb))
      err("usb_submit_urb(read bulk) failed");

    port->interrupt_in_urb->dev = port->serial->dev;
    if(usb_submit_urb(port->interrupt_in_urb))
      err(" usb_submit_urb(read int) failed");
  }

  spin_unlock_irqrestore(&port->port_lock, flags);

  return 0;
} /* prolific_sa_open */

static void prolific_sa_close(struct usb_serial_port *port, struct file *filp)
{
  unsigned long flags;

  dbg(__FUNCTION__ " port %d", port->number);

  spin_lock_irqsave(&port->port_lock, flags);

  --port->open_count;
  MOD_DEC_USE_COUNT;

  if(port->open_count <= 0) {
    /* shutdown our bulk reads and writes */
    usb_unlink_urb(port->write_urb);
    usb_unlink_urb(port->read_urb);
    usb_unlink_urb(port->interrupt_in_urb); /* wgg - do I need this? I think so. */
    port->active = 0;
  }

  spin_unlock_irqrestore(&port->port_lock, flags);
} /* prolific_sa_close */

static void prolific_sa_read_int_callback(struct urb *urb)
{
  struct usb_serial_port      *port = (struct usb_serial_port *)urb->context;
  struct prolific_sa_private  *priv = (struct prolific_sa_private *)port->private;
  struct usb_serial           *serial;
  unsigned char               *data = urb->transfer_buffer;

  /* the urb might have been killed. */
  if(urb->status)
    return;

  if(port_paranoia_check(port, "prolific_sa_read_interrupt"))
    return;

  serial = port->serial;
  if(serial_paranoia_check(serial, "prolific_sa_read_interrupt"))
    return;

  usb_serial_debug_data(__FILE__, __FUNCTION__, urb->actual_length, data);

  /* Handle known interrupt data */

  /* ignore data[0] and data[1] */
  priv->last_msr = data[PROLIFIC_SA_MSR_INDEX];
  dbg("interrupt: 0x%02x", priv->last_msr);

  /* Record Control Line states */
  if(priv->last_msr & PROLIFIC_SA_MSR_DSR)
    priv->control_state |= TIOCM_DSR;
  else
    priv->control_state &= ~TIOCM_DSR;

  if(priv->last_msr & PROLIFIC_SA_MSR_CTS)
    priv->control_state |= TIOCM_CTS;
  else
    priv->control_state &= ~TIOCM_CTS;

  if(priv->last_msr & PROLIFIC_SA_MSR_RI)
    priv->control_state |= TIOCM_RI;
  else
    priv->control_state &= ~TIOCM_RI;

  if(priv->last_msr & PROLIFIC_SA_MSR_CD)
    priv->control_state |= TIOCM_CD;
  else
    priv->control_state &= ~TIOCM_CD;

  /* Now to report any errors */
  priv->last_lsr = data[PROLIFIC_SA_LSR_INDEX];
#if 0
  if(priv->last_lsr & PROLIFIC_SA_LSR_ERR) {
    tty = port->tty;

    /* Overrun Error */
    if(priv->last_lsr & PROLIFIC_SA_LSR_OE) {
    }

    /* Parity Error */
    if(priv->last_lsr & PROLIFIC_SA_LSR_PE) {
    }

    /* Framing Error */
    if(priv->last_lsr & PROLIFIC_SA_LSR_FE) {
    }

    /* Break Indicator */
    if(priv->last_lsr & PROLIFIC_SA_LSR_BI) {
    }
  }
#endif
  /* INT urbs are automatically re-submitted */
}

static void prolific_sa_set_termios(struct usb_serial_port *port, struct termios *old_termios)
{
  struct usb_serial           *serial = port->serial;
  struct prolific_sa_private  *priv = (struct prolific_sa_private *)port->private;
  unsigned int                cflag = port->tty->termios->c_cflag;
  unsigned int                old_cflag = old_termios->c_cflag;
  unsigned long               rate = 115200;
  unsigned char               format = 0, parity = 0, size = 8;

  info(__FUNCTION__ " - cflag: 0x%4X, old_cflag: 0x%4X", cflag, old_cflag);

  /* Set the baud rate */
  if((cflag & CBAUD) != (old_cflag & CBAUD)) {
    /* reassert DTR and (maybe) RTS on transition from B0 */
    if((old_cflag & CBAUD) == B0) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -