Back to home page

Quest Cross Reference

 
 

    


Warning, cross-references for /kernel/drivers/usb/net.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/net/ethernet.h>
0021 #include <util/printf.h>
0022 #include <kernel.h>
0023 #include "sched/sched.h"
0024 
0025 #define DEBUG_USB_NET
0026 
0027 #ifdef DEBUG_USB_NET
0028 #define DLOG(fmt,...) DLOG_PREFIX("USB-net",fmt,##__VA_ARGS__)
0029 #else
0030 #define DLOG(fmt,...) ;
0031 #endif
0032 
0033 #define CDC_TYPE_CS_INTERFACE 0x24
0034 
0035 #define CDC_SUBTYPE_HEADER 0x00
0036 #define CDC_SUBTYPE_UNION  0x06
0037 #define CDC_SUBTYPE_ETHERNET 0x0F
0038 
0039 
0040 struct cdc_header_fundesc {
0041   uint8 bFunctionLength;
0042   uint8 bDescriptorType;
0043   uint8 bDescriptorSubtype;
0044   uint16 bcdCDC;
0045 } PACKED;
0046 typedef struct cdc_header_fundesc CDC_HEADER_FUNDESC;
0047 
0048 struct cdc_union_fundesc {
0049   uint8 bFunctionLength;
0050   uint8 bDescriptorType;
0051   uint8 bDescriptorSubtype;
0052   uint8 bControlInterface;
0053   uint8 bSubordinateInterface[];
0054 } PACKED;
0055 typedef struct cdc_union_fundesc CDC_UNION_FUNDESC;
0056 
0057 struct cdc_ethernet_fundesc {
0058   uint8 bFunctionLength;
0059   uint8 bDescriptorType;
0060   uint8 bDescriptorSubtype;
0061   uint8 iMACAddress;
0062   uint32 bmEthernetStatistics;
0063   uint16 wMaxSegmentSize;
0064   uint16 wNumberMCFilters;
0065   uint8 bNumberPowerFilters;
0066 } PACKED;
0067 typedef struct cdc_ethernet_fundesc CDC_ETHERNET_FUNDESC;
0068 
0069 typedef union {
0070   struct {
0071     uint8 bFunctionLength;
0072     uint8 bDescriptorType;
0073     uint8 bDescriptorSubtype;
0074   };
0075   CDC_HEADER_FUNDESC   header;
0076   CDC_UNION_FUNDESC    cdc_union;
0077   CDC_ETHERNET_FUNDESC ethernet;
0078 } CDC_FUNDESC;
0079 
0080 static inline uint8
0081 hex2byte (uint8 h[2])
0082 {
0083   return
0084     (('0' <= h[0] && h[0] <= '9') ? h[0] - '0' : h[0] - 'A' + 10) * 16 +
0085     (('0' <= h[1] && h[1] <= '9') ? h[1] - '0' : h[1] - 'A' + 10);
0086 }
0087 
0088 static uint8 ethaddr[6];
0089 static uint status_ept, status_maxpkt;
0090 static uint data_ept_in, data_ept_out, data_maxpkt;
0091 static uint data_iface, data_nop_alt, data_real_alt;
0092 static USB_DEVICE_INFO *ethusbdev;
0093 static ethernet_device usbnet_ethdev;
0094 
0095 static bool
0096 reset (void)
0097 {
0098   if (usb_set_interface (ethusbdev, data_nop_alt, data_iface) != 0) {
0099     DLOG ("set_interface -> nop data: failed");
0100     return FALSE;
0101   }
0102 
0103   if (usb_set_interface (ethusbdev, data_real_alt, data_iface) != 0) {
0104     DLOG ("set_interface -> real data: failed");
0105     return FALSE;
0106   }
0107 
0108   return TRUE;
0109 }
0110 
0111 static bool
0112 get_hwaddr (uint8 addr[ETH_ADDR_LEN])
0113 {
0114   int i;
0115   for (i=0; i<ETH_ADDR_LEN; i++)
0116     addr[i] = ethaddr[i];
0117   return TRUE;
0118 }
0119 
0120 static sint
0121 transmit (uint8* buf, sint len)
0122 {
0123   sint ret;
0124   uint32 act_len;
0125 
0126   DLOG ("transmitting data len=%d: %.02X %.02X %.02X %.02X", len,
0127         buf[0], buf[1], buf[2], buf[3]);
0128   if (usb_bulk_transfer (ethusbdev, data_ept_out, buf, len,
0129                          data_maxpkt, DIR_OUT, &act_len) == 0)
0130     ret = len;
0131   else
0132     ret = 0;
0133 
0134   return ret;
0135 }
0136 
0137 static void
0138 poll (void)
0139 {
0140   uint8 buffer[1600];
0141   uint32 act_len;
0142   if (usb_bulk_transfer (ethusbdev, data_ept_in, buffer, 1514,
0143                          data_maxpkt, DIR_IN, &act_len) == 0) {
0144     if (act_len > 0) {
0145       DLOG ("receiving data len=%d: %.02X %.02X %.02X %.02X",
0146             act_len, buffer[0], buffer[1], buffer[2], buffer[3]);
0147       usbnet_ethdev.recv_func (&usbnet_ethdev, buffer, act_len);
0148     }
0149   }
0150 }
0151 
0152 static void
0153 irq_loop (void)
0154 {
0155   uint32 tick = 0;
0156   DLOG ("irq_loop pid=0x%x", str ());
0157   for (;;) {
0158     poll ();
0159     DLOG ("iteration %d", tick);
0160     tick++;
0161   }
0162 }
0163 
0164 static uint32 irq_stack[1024] ALIGNED(0x1000);
0165 static task_id irq_pid;
0166 
0167 static bool
0168 probe (USB_DEVICE_INFO *info, USB_CFG_DESC *cfgd, USB_IF_DESC *ifd)
0169 {
0170   uint i;
0171   uint8 addrstr[13] = { [12] = 0 };
0172   uint8 strbuf[26];
0173   CDC_FUNDESC *fund = (CDC_FUNDESC *)&ifd[1];
0174   CDC_ETHERNET_FUNDESC *ethd;
0175   USB_EPT_DESC *eptd;
0176 
0177   if (!(ifd->bInterfaceClass == 0x02 &&
0178         ifd->bInterfaceSubClass == 0x06 &&
0179         ifd->bInterfaceProtocol == 0x00))
0180     return FALSE;
0181 
0182   while (fund->bDescriptorType == CDC_TYPE_CS_INTERFACE) {
0183     DLOG ("found functional desc. subtype=0x%x", fund->bDescriptorSubtype);
0184     switch (fund->bDescriptorSubtype) {
0185     case CDC_SUBTYPE_ETHERNET:
0186       ethd = &fund->ethernet;
0187       DLOG ("eth iMAC=%d mss=%d", ethd->iMACAddress, ethd->wMaxSegmentSize);
0188       if (usb_get_descriptor (info, USB_TYPE_STR_DESC, ethd->iMACAddress, 0,
0189                               sizeof (strbuf), strbuf) != 0) {
0190         DLOG ("unable to get ethernet address");
0191         return FALSE;
0192       }
0193       /* seems to be UTF-16 encoded */
0194       for (i=0; i<12; i++)
0195         addrstr[i] = strbuf[2*i+2];
0196       for (i=0; i<6; i++)
0197         ethaddr[i] = hex2byte (&addrstr[2*i]);
0198       DLOG ("ethernet string=%s address=%.02X:%.02X:%.02X:%.02X:%.02X:%.02X",
0199             addrstr, ethaddr[0], ethaddr[1], ethaddr[2],
0200             ethaddr[3], ethaddr[4], ethaddr[5]);
0201       break;
0202     }
0203     fund = (CDC_FUNDESC *)((uint8 *)fund + fund->bFunctionLength);
0204   }
0205 
0206   /* expect fund to point to an endpoint (Status) */
0207   if (fund->bDescriptorType != USB_TYPE_EPT_DESC) {
0208     DLOG ("did not find Status endpoint: bDescriptorType=0x%x",
0209           fund->bDescriptorType);
0210     return FALSE;
0211   }
0212 
0213   eptd = (USB_EPT_DESC *)fund;
0214   status_ept = eptd->bEndpointAddress & 0x7F;
0215   status_maxpkt = eptd->wMaxPacketSize;
0216 
0217   /* expect CDC Data (nop) to follow */
0218   ifd = (USB_IF_DESC *) &eptd[1];
0219 
0220   if (ifd->bDescriptorType != USB_TYPE_IF_DESC) {
0221     DLOG ("did not find CDC Data (nop): bDescriptorType=0x%x",
0222           ifd->bDescriptorType);
0223     return FALSE;
0224   }
0225 
0226   data_iface = ifd->bInterfaceNumber;
0227   data_nop_alt = ifd->bAlternateSetting;
0228 
0229   /* then CDC Data (actual) */
0230   ifd = &ifd[1];
0231 
0232   if (ifd->bDescriptorType != USB_TYPE_IF_DESC) {
0233     DLOG ("did not find CDC Data: bDescriptorType=0x%x",
0234           ifd->bDescriptorType);
0235     return FALSE;
0236   }
0237 
0238   data_real_alt = ifd->bAlternateSetting;
0239 
0240   DLOG ("CDC Data (nop) iface#=%d alt=%d.  CDC Data alt=%d",
0241         data_iface, data_nop_alt, data_real_alt);
0242 
0243   /* now two endpoints for data */
0244   eptd = (USB_EPT_DESC *) &ifd[1];
0245   data_maxpkt = eptd->wMaxPacketSize;
0246   if (eptd->bEndpointAddress & 0x80)
0247     data_ept_in = eptd->bEndpointAddress & 0x7F;
0248   else
0249     data_ept_out = eptd->bEndpointAddress & 0x7F;
0250 
0251   eptd = &eptd[1];
0252   if (data_maxpkt != eptd->wMaxPacketSize) {
0253     DLOG ("cannot handle: in/out packet sizes differ");
0254     return FALSE;
0255   }
0256   if (eptd->bEndpointAddress & 0x80)
0257     data_ept_in = eptd->bEndpointAddress & 0x7F;
0258   else
0259     data_ept_out = eptd->bEndpointAddress & 0x7F;
0260 
0261   DLOG ("data_ept_in=%d data_ept_out=%d data_maxpkt=%d",
0262         data_ept_in, data_ept_out, data_maxpkt);
0263   if (usb_set_configuration (info, cfgd->bConfigurationValue) != 0) {
0264     DLOG ("set_configuration: failed");
0265     return FALSE;
0266   }
0267 
0268   ethusbdev = info;
0269 
0270   if (!reset ())
0271     return FALSE;
0272 
0273   /* Register network device with net subsystem */
0274   usbnet_ethdev.recv_func = NULL;
0275   usbnet_ethdev.send_func = transmit;
0276   usbnet_ethdev.get_hwaddr_func = get_hwaddr;
0277   usbnet_ethdev.poll_func = poll;
0278 
0279   if (!net_register_device (&usbnet_ethdev)) {
0280     DLOG ("registration failed");
0281     return FALSE;
0282   }
0283 
0284   irq_pid = start_kernel_thread ((uint) irq_loop, (uint) &irq_stack[1023]);
0285 
0286   return TRUE;
0287 }
0288 
0289 static USB_DRIVER net_driver = {
0290   .probe = probe
0291 };
0292 
0293 extern bool
0294 usb_net_driver_init (void)
0295 {
0296   return usb_register_driver (&net_driver);
0297 }
0298 
0299 #include "module/header.h"
0300 
0301 static const struct module_ops mod_ops = {
0302   .init = usb_net_driver_init
0303 };
0304 
0305 DEF_MODULE (usb___net, "USB net driver", &mod_ops, {"usb", "net___ethernet"});
0306 
0307 
0308 /*
0309  * Local Variables:
0310  * indent-tabs-mode: nil
0311  * mode: C
0312  * c-file-style: "gnu"
0313  * c-basic-offset: 2
0314  * End:
0315  */
0316 
0317 /* vi: set et sw=2 sts=2: */