Back to home page

Quest Cross Reference

 
 

    


Warning, cross-references for /kernel/drivers/usb/ftdi.c need to be fixed.

0001 /*                    The Quest Operating System
0002  *  Copyright (C) 2005-2010  Richard West, Boston University
0003  *
0004  *  This program is free software: you can redistribute it and/or modify
0005  *  it under the terms of the GNU General Public License as published by
0006  *  the Free Software Foundation, either version 3 of the License, or
0007  *  (at your option) any later version.
0008  *
0009  *  This program is distributed in the hope that it will be useful,
0010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
0011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0012  *  GNU General Public License for more details.
0013  *
0014  *  You should have received a copy of the GNU General Public License
0015  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
0016  */
0017 
0018 #include <drivers/usb/usb.h>
0019 #include <drivers/usb/uhci.h>
0020 #include <drivers/usb/ftdi.h>
0021 #include <arch/i386.h>
0022 #include <util/printf.h>
0023 #include <kernel.h>
0024 
0025 #define DEBUG_FTDI
0026 
0027 #ifdef DEBUG_FTDI
0028 #define DLOG(fmt,...) DLOG_PREFIX("ftdi",fmt,##__VA_ARGS__)
0029 #else
0030 #define DLOG(fmt,...) ;
0031 #endif
0032 
0033 /* The Base Clock of the chip. It is either 12000000 or 48000000. */
0034 #define FTDI_BASE_CLOCK    48000000
0035 
0036 static USB_DEVICE_INFO ftdi_dev;
0037 static uint8_t in_ept = 0, out_ept = 0;
0038 
0039 bool usb_ftdi_driver_init (void);
0040 void usb_ftdi_putc (char);
0041 char usb_ftdi_getc (void);
0042 int usb_ftdi_write (unsigned char *, uint32_t);
0043 int usb_ftdi_read (unsigned char *, uint32_t);
0044 
0045 /*
0046  * Reset FTDI chip. Always set port to 0? The Linux driver
0047  * says this is 0 for FT232/245. For now, we are supposed to
0048  * support only FT232.
0049  */
0050 static int
0051 ftdi_reset (USB_DEVICE_INFO * dev, uint16_t port)
0052 {
0053   USB_DEV_REQ req;
0054   req.bmRequestType = 0x40;
0055   req.bRequest = USB_FTDI_RESET;
0056   /* wValue = 0  :  Reset
0057    * wValue = 1  :  Purge RX buffer
0058    * wValue = 2  :  Purge TX buffer
0059    */
0060   req.wValue = 0;
0061   req.wIndex = port;
0062   req.wLength = 0;
0063 
0064   return usb_control_transfer (dev, (addr_t) & req,
0065       sizeof (USB_DEV_REQ), 0, 0);
0066 }
0067 
0068 /* Get the divisor which is later used to set the baud rate */
0069 /* This function is from the Linux FTDI driver */
0070 static uint32_t
0071 ftdi_baud_base_to_divisor (uint32_t baud, uint32_t base)
0072 {
0073   static const unsigned char divfrac[8] = { 0, 3, 2, 4, 1, 5, 6, 7 };
0074   uint32_t divisor;
0075   /* divisor shifted 3 bits to the left */
0076   int divisor3 = base / 2 / baud;
0077   divisor = divisor3 >> 3;
0078   divisor |= (uint32_t)divfrac[divisor3 & 0x7] << 14;
0079   /* Deal with special cases for highest baud rates. */
0080   if (divisor == 1)
0081     divisor = 0;
0082   else if (divisor == 0x4001)
0083     divisor = 1;
0084   return divisor;
0085 }
0086 
0087 static int
0088 ftdi_set_baud (USB_DEVICE_INFO * dev, uint32_t baud, uint16_t port)
0089 {
0090   USB_DEV_REQ req;
0091   uint32_t divisor = ftdi_baud_base_to_divisor (baud, FTDI_BASE_CLOCK);
0092 
0093   req.bmRequestType = 0x40;
0094   req.bRequest = USB_FTDI_SET_BAUD_RATE;
0095   req.wValue = divisor;
0096   req.wIndex = port;
0097   req.wLength = 0;
0098 
0099   return usb_control_transfer (dev, (addr_t) & req,
0100       sizeof (USB_DEV_REQ), 0, 0);
0101 }
0102 
0103 /* Setting FTDI data characteristics */
0104 static int
0105 ftdi_set_data (
0106     USB_DEVICE_INFO * dev,
0107     uint8_t bits, /* Number of data bits */
0108     uint8_t parity, /* 0 = None, 1 = Odd, 2 = Even, 3 = Mark, 4 = Space */
0109     uint8_t stb, /* Stop Bits 0 = 1, 1 = 1.5, 2 = 2 */
0110     uint8_t tx, /* 1 = TX ON (break), 0 = TX OFF (normal state) */
0111     uint16_t port)
0112 {
0113   USB_DEV_REQ req;
0114   uint16_t dc = (tx & 0x1) << 14 |
0115     (stb & 0x7) << 11 | (parity & 0x7) << 8 | bits;
0116 
0117   req.bmRequestType = 0x40;
0118   req.bRequest = USB_FTDI_SET_DATA;
0119   req.wValue = dc;
0120   req.wIndex = port;
0121   req.wLength = 0;
0122 
0123   return usb_control_transfer (dev, (addr_t) & req,
0124       sizeof (USB_DEV_REQ), 0, 0);
0125 }
0126 
0127 static uint16_t
0128 ftdi_modem_status (USB_DEVICE_INFO * dev, uint16_t port)
0129 {
0130   USB_DEV_REQ req;
0131   uint16_t status;
0132 
0133   req.bmRequestType = 0xC0;
0134   req.bRequest = USB_FTDI_GET_MODEM_STATUS;
0135   req.wValue = 0;
0136   req.wIndex = port;
0137   req.wLength = 2;
0138 
0139   if (usb_control_transfer (dev, (addr_t) & req,
0140         sizeof (USB_DEV_REQ), (addr_t) & status, req.wLength)) {
0141     DLOG ("Get modem status failed");
0142     return 0xFFFF;
0143   }
0144 
0145   return status;
0146 }
0147 
0148 static int
0149 ftdi_set_flow_ctl (USB_DEVICE_INFO * dev, uint16_t port, uint8_t ctrl)
0150 {
0151   USB_DEV_REQ req;
0152 
0153   req.bmRequestType = 0x40;
0154   req.bRequest = USB_FTDI_SET_FLOW_CTRL;
0155   req.wValue = 0;
0156   req.wIndex = (ctrl << 8) + port;
0157   req.wLength = 0;
0158 
0159   return usb_control_transfer (dev, (addr_t) & req,
0160       sizeof (USB_DEV_REQ), 0, 0);
0161 }
0162 
0163 /* Set the timeout interval. The default is 16 ms */
0164 static int
0165 ftdi_set_latency (USB_DEVICE_INFO * dev, uint16_t port, uint8_t latency)
0166 {
0167   USB_DEV_REQ req;
0168 
0169   req.bmRequestType = 0x40;
0170   req.bRequest = USB_FTDI_SET_LATENCY_TIMER;
0171   req.wValue = latency; /* Latency in milliseconds */
0172   req.wIndex = port;
0173   req.wLength = 0;
0174 
0175   return usb_control_transfer (dev, (addr_t) & req,
0176       sizeof (USB_DEV_REQ), 0, 0);
0177 }
0178 
0179 static uint8_t
0180 ftdi_get_latency (USB_DEVICE_INFO * dev, uint16_t port)
0181 {
0182   USB_DEV_REQ req;
0183   uint8_t latency = 0;
0184 
0185   req.bmRequestType = 0xC0;
0186   req.bRequest = USB_FTDI_GET_LATENCY_TIMER;
0187   req.wValue = 0;
0188   req.wIndex = port;
0189   req.wLength = 1;
0190 
0191   if (usb_control_transfer (dev, (addr_t) & req,
0192       sizeof (USB_DEV_REQ), (addr_t) & latency, 1)) {
0193     DLOG ("Getting latency timer failed!");
0194     return 0;
0195   }
0196 
0197   return latency;
0198 }
0199 
0200 static bool
0201 ftdi_init (USB_DEVICE_INFO *dev, USB_CFG_DESC *cfg, USB_IF_DESC *ifd)
0202 {
0203   uint8_t tmp[50];
0204   int i = 0;
0205   uint16_t mod_stat = 0;
0206   uint8_t latency = 0;
0207   USB_EPT_DESC *ftdiept;
0208 
0209   ftdi_dev = *(dev);
0210   memset (tmp, 0, 50);
0211 
0212   /* Parsing endpoints */
0213   DLOG ("Parsing FTDI chip endpoints ...");
0214   usb_get_descriptor (dev, USB_TYPE_CFG_DESC, 0, 0, cfg->wTotalLength,
0215       (addr_t)tmp);
0216   for (i = 0; i < cfg->wTotalLength; i += ftdiept->bLength) {
0217     ftdiept = (USB_EPT_DESC *) (tmp + i);
0218     if ((ftdiept->bDescriptorType == USB_TYPE_EPT_DESC) &&
0219         ((ftdiept->bmAttributes & 0x3) == 0x2)) {
0220       DLOG ("Found Bulk Endpoint");
0221       switch (ftdiept->bEndpointAddress & 0x80) {
0222         case 0x80 :
0223           in_ept = ftdiept->bEndpointAddress & 0xF;
0224           DLOG ("IN Endpoint. Address is: 0x%X", in_ept);
0225           break;
0226 
0227         case 0x00 :
0228           out_ept = ftdiept->bEndpointAddress & 0xF;
0229           DLOG ("OUT Endpoint. Address is: 0x%X", out_ept);
0230           break;
0231 
0232         default :
0233           break;
0234       }
0235     }
0236   }
0237 
0238   /* Reset the chip */
0239   DLOG ("Resetting FTDI chip ...");
0240   if (ftdi_reset (dev, 0)) {
0241     DLOG ("Chip reset failed!");
0242     return FALSE;
0243   }
0244 
0245   /* Set the baud rate for the serial port */
0246   DLOG ("Setting baud rate ...");
0247   if (ftdi_set_baud (dev, 38400, 0)) {
0248     DLOG ("Setting baud rate failed!");
0249     return FALSE;
0250   }
0251 
0252   /* Set data characteristics */
0253   DLOG ("Setting data characteristics ...");
0254   if (ftdi_set_data (dev, 8, 0, 0, 0, 0)) {
0255     DLOG ("Setting data characteristics failed!");
0256     return FALSE;
0257   }
0258 
0259   /* Set timeout interval */
0260   DLOG ("Setting latency timer ...");
0261   if (ftdi_set_latency (dev, 0, 16)) {
0262     DLOG ("Setting latency timer failed!");
0263     return FALSE;
0264   }
0265 
0266   /* Get timeout interval */
0267   DLOG ("Getting latency timer ...");
0268   if ((latency = ftdi_get_latency (dev, 0))) {
0269     DLOG ("Current timeout interval is: %d", latency);
0270   }
0271 
0272   /* Set flow control */
0273   DLOG ("Setting flow control ...");
0274   if (ftdi_set_flow_ctl (dev, 0, USB_FTDI_NO_FLOW_CTRL)) {
0275     DLOG ("Setting flow control failed!");
0276     return FALSE;
0277   }
0278 #if 1
0279   /* Get modem status */
0280   DLOG ("Getting modem status ...");
0281   if ((mod_stat = ftdi_modem_status (dev, 0)) == 0xFFFF) {
0282     DLOG ("Getting modem status failed!");
0283     return FALSE;
0284   } else {
0285     DLOG ("Modem status is: 0x%X", mod_stat);
0286   }
0287 #endif
0288   return TRUE;
0289 }
0290 
0291 static void
0292 ftdi_test (void)
0293 {
0294   DLOG ("FTDI Tests");
0295   char c = 0;
0296 
0297   usb_ftdi_putc ('!');
0298 
0299   while (c != 0xD) {
0300     c = usb_ftdi_getc ();
0301     DLOG ("Got character : %c", c);
0302     usb_ftdi_putc (c);
0303   }
0304 }
0305 
0306 static bool
0307 ftdi_probe (USB_DEVICE_INFO *dev, USB_CFG_DESC *cfg, USB_IF_DESC *ifd)
0308 {
0309   if (dev->devd.idVendor == 0x0403) {
0310     DLOG ("An FTDI chip is detected");
0311 
0312     if (dev->devd.idProduct != 0x6001) {
0313       DLOG ("FT232 not found. Product ID is: 0x%X",
0314           dev->devd.idProduct);
0315       return FALSE;
0316     }
0317   } else {
0318     return FALSE;
0319   }
0320 
0321   if (!ftdi_init(dev, cfg, ifd)) {
0322     DLOG("Initialization failed!");
0323     return FALSE;
0324   }
0325 
0326   DLOG ("FTDI Serial Converter configured");
0327   //ftdi_test();
0328 
0329   return TRUE;
0330 }
0331 
0332 char
0333 usb_ftdi_getc (void)
0334 {
0335   unsigned char buf[3];
0336   int act_len = 0;
0337 
0338   if ((act_len = usb_ftdi_read (buf, 3)) != 3) {
0339     DLOG ("usb_ftdi_read () failed. %d bytes returned.", act_len);
0340     return '\0';
0341   }
0342 
0343   return buf[2];
0344 }
0345 
0346 void
0347 usb_ftdi_putc (char c)
0348 {
0349   unsigned char buf[2];
0350   int count = 0, buf_size = 0;
0351 
0352 #if 0
0353   /* This is not necessary for newer chips */
0354   /* First byte is reserved, it contains length and Port ID */
0355   /* B0 = 1, B1 = 0, B2..7 = Length of Message */
0356   buf[0] = (1 << 2) | 1;
0357   /* Actual data to be transfered */
0358   buf[1] = c;
0359   buf_size = 2;
0360 #else
0361   buf[0] = c;
0362   buf_size = 1;
0363 #endif
0364 
0365   if ((count = usb_ftdi_write (buf, buf_size)) != buf_size)
0366     DLOG ("usb_ftdi_putc failed, %d bytes sent", count);
0367   else
0368     DLOG ("usb_ftdi_putc done, %d bytes sent", count);
0369 }
0370 
0371 int
0372 usb_ftdi_write (unsigned char * buf, uint32_t len)
0373 {
0374   uint32_t act_len = 0;
0375   int status = 0;
0376 
0377   if ((status = usb_bulk_transfer (&ftdi_dev, out_ept, (addr_t) buf,
0378         len, 64, DIR_OUT, &act_len)))
0379     DLOG ("Bulk write failed. Error Code: 0x%X", status);
0380   
0381   return act_len;
0382 }
0383 
0384 /*
0385  * First two bytes read contains modem status and line status.
0386  *
0387  * Byte 0: Modem Status
0388  *
0389  * Offset       Description
0390  * B0   Reserved - must be 1
0391  * B1   Reserved - must be 0
0392  * B2   Reserved - must be 0
0393  * B3   Reserved - must be 0
0394  * B4   Clear to Send (CTS)
0395  * B5   Data Set Ready (DSR)
0396  * B6   Ring Indicator (RI)
0397  * B7   Receive Line Signal Detect (RLSD)
0398  *
0399  * Byte 1: Line Status
0400  *
0401  * Offset       Description
0402  * B0   Data Ready (DR)
0403  * B1   Overrun Error (OE)
0404  * B2   Parity Error (PE)
0405  * B3   Framing Error (FE)
0406  * B4   Break Interrupt (BI)
0407  * B5   Transmitter Holding Register (THRE)
0408  * B6   Transmitter Empty (TEMT)
0409  * B7   Error in RCVR FIFO
0410  */
0411 int
0412 usb_ftdi_read (unsigned char * buf, uint32_t len)
0413 {
0414   uint32_t act_len = 0;
0415   int status = 0;
0416 
0417   if ((status = usb_bulk_transfer (&ftdi_dev, in_ept, (addr_t) buf,
0418         len, 64, DIR_IN, &act_len)))
0419     DLOG ("Bulk read failed. Error Code: 0x%X", status);
0420   
0421   return act_len;
0422 }
0423 
0424 static USB_DRIVER ftdi_driver = {
0425   .probe = ftdi_probe
0426 };
0427 
0428 bool
0429 usb_ftdi_driver_init (void)
0430 {
0431   return usb_register_driver (&ftdi_driver);
0432 }
0433 
0434 #include "module/header.h"
0435 
0436 static const struct module_ops mod_ops = {
0437   .init = usb_ftdi_driver_init
0438 };
0439 
0440 DEF_MODULE (usb___ftdi, "USB FTDI driver", &mod_ops, {"usb"});
0441 
0442 /*
0443  * Local Variables:
0444  * indent-tabs-mode: nil
0445  * mode: C
0446  * c-file-style: "gnu"
0447  * c-basic-offset: 2
0448  * End:
0449  */
0450 
0451 /* vi: set et sw=2 sts=2: */