Back to home page

Quest Cross Reference

 
 

    


Warning, cross-references for /kernel/drivers/usb/pl2303.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/pl2303.h>
0021 #include <arch/i386.h>
0022 #include <util/printf.h>
0023 #include <kernel.h>
0024 
0025 #define DEBUG_PL2303
0026 
0027 #ifdef DEBUG_PL2303
0028 #define DLOG(fmt,...) DLOG_PREFIX("pl2303",fmt,##__VA_ARGS__)
0029 #else
0030 #define DLOG(fmt,...) ;
0031 #endif
0032 
0033 static USB_DEVICE_INFO pl2303_dev;
0034 static uint8_t in_ept = 0, out_ept = 0;
0035 
0036 int usb_pl2303_write (unsigned char *, uint32_t);
0037 void usb_pl2303_putc (char);
0038 int usb_pl2303_read (unsigned char *, uint32_t);
0039 char usb_pl2303_getc (void);
0040 
0041 /* Flow control setting */
0042 static int
0043 pl2303_set_control (USB_DEVICE_INFO * dev, uint8_t on)
0044 {
0045   USB_DEV_REQ req;
0046   uint8_t control = 0;
0047 
0048   if (on)
0049     control |= (USB_PL2303_CONTROL_DTR | USB_PL2303_CONTROL_RTS);
0050   else
0051     control &= ~(USB_PL2303_CONTROL_DTR | USB_PL2303_CONTROL_RTS);
0052 
0053   req.bmRequestType = 0x21;
0054   req.bRequest = USB_PL2303_SET_CONTROL;
0055   req.wValue = control;
0056   req.wIndex = 0;
0057   req.wLength = 0;
0058 
0059   return usb_control_transfer (dev, (addr_t) & req,
0060       sizeof (USB_DEV_REQ), 0, 0);
0061 }
0062 
0063 static PL2303_CONFIG
0064 pl2303_get_line (USB_DEVICE_INFO * dev)
0065 {
0066   USB_DEV_REQ req;
0067   PL2303_CONFIG data;
0068   memset (&data, 0, sizeof (PL2303_CONFIG));
0069 
0070   req.bmRequestType = 0xA1;
0071   req.bRequest = USB_PL2303_GET_LINE;
0072   req.wValue = 0;
0073   req.wIndex = 0;
0074   req.wLength = 7;
0075 
0076   if (usb_control_transfer (dev, (addr_t) & req, sizeof (USB_DEV_REQ),
0077       (addr_t) & data, req.wLength)) {
0078     DLOG ("pl2303_get_line failed!");
0079     memset (&data, 0, sizeof (PL2303_CONFIG));
0080   }
0081 
0082   return data;
0083 }
0084 
0085 static int
0086 pl2303_set_line (
0087     USB_DEVICE_INFO * dev,
0088     uint32_t baud,
0089     uint8_t bits, /* Number of data bits */
0090     uint8_t parity, /* 0 = None, 1 = Odd, 2 = Even, 3 = Mark, 4 = Space */
0091     uint8_t stb) /* Stop Bits 0 = 1, 1 = 1.5, 2 = 2 */
0092 {
0093   USB_DEV_REQ req;
0094   PL2303_CONFIG data;
0095   memset (&data, 0, sizeof (PL2303_CONFIG));
0096 
0097   data = pl2303_get_line (dev);
0098   
0099   if (data.baud_rate) {
0100     DLOG ("Current baud rate: %d", data.baud_rate);
0101     DLOG ("Current Stop Bits (0=1,1=1.5,2=2): %d", data.stop_bits);
0102     DLOG ("Current Parity (0=none,1=odd,2=even,3=mark,4=space): %d",
0103         data.parity);
0104     DLOG ("Current Data Bits: %d", data.data_bits);
0105   }
0106 
0107   data.baud_rate = baud;
0108   data.stop_bits = stb;
0109   data.parity = parity;
0110   data.data_bits = bits;
0111 
0112   req.bmRequestType = 0x21;
0113   req.bRequest = USB_PL2303_SET_LINE;
0114   req.wValue = 0;
0115   req.wIndex = 0;
0116   req.wLength = 7;
0117 
0118   return usb_control_transfer (dev, (addr_t) & req,
0119       sizeof (USB_DEV_REQ), (addr_t) & data, req.wLength);
0120 }
0121 
0122 static bool
0123 pl2303_init (USB_DEVICE_INFO *dev, USB_CFG_DESC *cfg, USB_IF_DESC *ifd)
0124 {
0125   uint8_t tmp[70];
0126   int i = 0;
0127   USB_EPT_DESC *pl2303ept;
0128   PL2303_CONFIG conf;
0129   memset (&conf, 0, sizeof (PL2303_CONFIG));
0130 
0131   pl2303_dev = *(dev);
0132   memset (tmp, 0, 70);
0133 
0134   /* Parsing endpoints */
0135   DLOG ("Parsing PL2303 chip endpoints ...");
0136   usb_get_descriptor (dev, USB_TYPE_CFG_DESC, 0, 0, cfg->wTotalLength,
0137       (addr_t)tmp);
0138   for (i = 0; i < cfg->wTotalLength; i += pl2303ept->bLength) {
0139     pl2303ept = (USB_EPT_DESC *) (tmp + i);
0140     if ((pl2303ept->bDescriptorType == USB_TYPE_EPT_DESC) &&
0141         ((pl2303ept->bmAttributes & 0x3) == 0x2)) {
0142       DLOG ("Found Bulk Endpoint");
0143       switch (pl2303ept->bEndpointAddress & 0x80) {
0144         case 0x80 :
0145           in_ept = pl2303ept->bEndpointAddress & 0xF;
0146           DLOG ("IN Endpoint. Address is: 0x%X", in_ept);
0147           break;
0148 
0149         case 0x00 :
0150           out_ept = pl2303ept->bEndpointAddress & 0xF;
0151           DLOG ("OUT Endpoint. Address is: 0x%X", out_ept);
0152           break;
0153 
0154         default :
0155           break;
0156       }
0157     }
0158   }
0159 
0160   /* Serial port configuration */
0161   DLOG ("Configuring serial interface (38400, 8N1)...");
0162   if (pl2303_set_line (dev, 38400, 8, 0, 0)) {
0163     DLOG ("Serial interface configuration failed");
0164     return FALSE;
0165   }
0166 
0167   DLOG ("Checking configuration ...");
0168   conf = pl2303_get_line (dev);
0169   
0170   DLOG ("Current baud rate: %d", conf.baud_rate);
0171   DLOG ("Current Stop Bits (0=1,1=1.5,2=2): %d", conf.stop_bits);
0172   DLOG ("Current Parity (0=none,1=odd,2=even,3=mark,4=space): %d",
0173       conf.parity);
0174   DLOG ("Current Data Bits: %d", conf.data_bits);
0175 
0176 #if 1
0177   /* Setting flow control */
0178   DLOG ("Setting flow control ...");
0179   if (pl2303_set_control (dev, 1)) {
0180     DLOG ("Setting flow control failed");
0181     return FALSE;
0182   }
0183 #endif
0184 
0185   return TRUE;
0186 }
0187 
0188 static void
0189 test ()
0190 {
0191   DLOG ("PL2303 Test\n");
0192 #if 1
0193   char c = 0;
0194   while (c != 0xD) {
0195     c = usb_pl2303_getc ();
0196     DLOG ("Got character : %c", c);
0197     usb_pl2303_putc (c);
0198   }
0199 #else
0200   usb_pl2303_putc ('Q');
0201   usb_pl2303_putc ('u');
0202   usb_pl2303_putc ('e');
0203   usb_pl2303_putc ('s');
0204   usb_pl2303_putc ('t');
0205 #endif
0206 }
0207 
0208 static bool
0209 pl2303_probe (USB_DEVICE_INFO *dev, USB_CFG_DESC *cfg, USB_IF_DESC *ifd)
0210 {
0211   if (dev->devd.idVendor == 0x067B) {
0212     DLOG ("Prolific Technology, Inc. device is detected");
0213 
0214     if (dev->devd.idProduct != 0x2303) {
0215       DLOG ("Device attached is not PL2303. Product ID is: 0x%X",
0216           dev->devd.idProduct);
0217       return FALSE;
0218     }
0219   } else {
0220     return FALSE;
0221   }
0222 
0223   if (!pl2303_init(dev, cfg, ifd)) {
0224     DLOG("Initialization failed!");
0225     return FALSE;
0226   }
0227 
0228   DLOG ("PL2303 Serial Converter configured");
0229 
0230   test();
0231 
0232   return TRUE;
0233 }
0234 
0235 void
0236 usb_pl2303_putc (char c)
0237 {
0238   unsigned char buf[1];
0239   int count = 0;
0240 
0241   buf[0] = c;
0242 
0243   if ((count = usb_pl2303_write (buf, 1)) != 1)
0244     DLOG ("usb_pl2303_putc failed, %d bytes sent", count);
0245   else
0246     DLOG ("usb_pl2303_putc done, %d bytes sent", count);
0247 }
0248 
0249 int
0250 usb_pl2303_write (unsigned char * buf, uint32_t len)
0251 {
0252   uint32_t act_len = 0;
0253   int status = 0;
0254 
0255   if ((status = usb_bulk_transfer (&pl2303_dev, out_ept, (addr_t) buf,
0256         len, 64, DIR_OUT, &act_len)))
0257     DLOG ("Bulk write failed. Error Code: 0x%X", status);
0258   
0259   return act_len;
0260 }
0261 
0262 char
0263 usb_pl2303_getc (void)
0264 {
0265   unsigned char buf[3];
0266   int act_len = 0;
0267 
0268   if ((act_len = usb_pl2303_read (buf, 1)) != 1) {
0269     DLOG ("usb_ftdi_read () failed. %d bytes returned.", act_len);
0270     return '\0';
0271   }
0272 
0273   return buf[0];
0274 }
0275 
0276 int
0277 usb_pl2303_read (unsigned char * buf, uint32_t len)
0278 {
0279   uint32_t act_len = 0;
0280   int status = 0;
0281 
0282   if ((status = usb_bulk_transfer (&pl2303_dev, in_ept, (addr_t) buf,
0283         len, 64, DIR_IN, &act_len)))
0284     DLOG ("Bulk read failed. Error Code: 0x%X", status);
0285 
0286   return act_len;
0287 }
0288 
0289 static USB_DRIVER pl2303_driver = {
0290   .probe = pl2303_probe
0291 };
0292 
0293 bool
0294 usb_pl2303_driver_init (void)
0295 {
0296   return usb_register_driver (&pl2303_driver);
0297 }
0298 
0299 #include "module/header.h"
0300 
0301 static const struct module_ops mod_ops = {
0302   .init = usb_pl2303_driver_init
0303 };
0304 
0305 DEF_MODULE (usb___pl2303, "USB pl2303 serial port driver", &mod_ops, {"usb"});
0306 
0307 /*
0308  * Local Variables:
0309  * indent-tabs-mode: nil
0310  * mode: C
0311  * c-file-style: "gnu"
0312  * c-basic-offset: 2
0313  * End:
0314  */
0315 
0316 /* vi: set et sw=2 sts=2: */