Back to home page

Quest Cross Reference

 
 

    


Warning, cross-references for /kernel/drivers/usb/asix.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_ASIX
0026 
0027 #ifdef DEBUG_ASIX
0028 #define DLOG(fmt,...) DLOG_PREFIX("asix",fmt,##__VA_ARGS__)
0029 #else
0030 #define DLOG(fmt,...) ;
0031 #endif
0032 
0033 static uint8 ethaddr[ETH_ADDR_LEN];
0034 static uint status_ept, status_maxpkt;
0035 static uint data_ept_in, data_ept_out, data_maxpkt;
0036 
0037 static USB_DEVICE_INFO *ethusbdev;
0038 static ethernet_device usbnet_ethdev;
0039 
0040 #define SOFTWARE_MII 0x06
0041 #define PHY_READ_REG 0x07
0042 #define PHY_WRITE_REG 0x08
0043 #define MII_STATUS 0x09
0044 #define HARDWARE_MII 0x0A
0045 #define RX_CTRL_READ 0x0F
0046 #define RX_CTRL_WRITE 0x10
0047 #define READ_IPG 0x11
0048 #define WRITE_IPG 0x12
0049 #define GET_NODE_ID 0x13
0050 #define ETH_PHY_ID 0x19
0051 #define MEDIUM_STATUS 0x1A
0052 #define MEDIUM_MODE 0x1B
0053 #define GPIO_WRITE 0x1F
0054 #define SW_RESET 0x20
0055 #define SW_PHY_SELECT 0x22
0056 
0057 #define SWRESET_CLEAR 0x00
0058 #define SWRESET_RR    0x01
0059 #define SWRESET_RT    0x02
0060 #define SWRESET_PRTE  0x04
0061 #define SWRESET_PRL   0x08
0062 #define SWRESET_BZ    0x10
0063 #define SWRESET_IPRL  0x20
0064 #define SWRESET_IPPD  0x40
0065 
0066 #define MII_BMCR 0x00
0067 #define MII_BMSR 0x01
0068 #define MII_PHYSID1 0x02
0069 #define MII_PHYSID2 0x03
0070 #define MII_ADVERTISE 0x04
0071 
0072 #define BMCR_RESET 0x8000
0073 #define BMCR_ANRESTART 0x0200
0074 #define BMCR_ANENABLE 0x1000
0075 #define BMCR_LOOPBACK 0x4000
0076 
0077 #define ADVERTISE_CSMA 0x0001
0078 #define ADVERTISE_10HALF  0x0020
0079 #define ADVERTISE_100HALF 0x0080
0080 #define ADVERTISE_10FULL 0x0040
0081 #define ADVERTISE_100FULL 0x100
0082 #define ADVERTISE_ALL (ADVERTISE_10HALF | ADVERTISE_10FULL | \
0083                        ADVERTISE_100HALF | ADVERTISE_100FULL)
0084 
0085 #define MEDIUM_PF   0x0080
0086 #define MEDIUM_JFE  0x0040
0087 #define MEDIUM_TFC  0x0020
0088 #define MEDIUM_RFC  0x0010
0089 #define MEDIUM_ENCK 0x0008
0090 #define MEDIUM_AC   0x0004
0091 #define MEDIUM_FD   0x0002
0092 #define MEDIUM_GM   0x0001
0093 #define MEDIUM_SM   0x1000
0094 #define MEDIUM_SBP  0x0800
0095 #define MEDIUM_PS   0x0200
0096 #define MEDIUM_RE   0x0100
0097 
0098 #define AX88772_MEDIUM_DEFAULT  \
0099         (MEDIUM_FD | MEDIUM_RFC | \
0100          MEDIUM_TFC | MEDIUM_PS | \
0101          MEDIUM_AC | MEDIUM_RE )
0102 
0103 /* GPIO 0 .. 2 toggles */
0104 #define GPIO_GPO0EN   0x01    /* GPIO0 Output enable */
0105 #define GPIO_GPO_0    0x02    /* GPIO0 Output value */
0106 #define GPIO_GPO1EN   0x04    /* GPIO1 Output enable */
0107 #define GPIO_GPO_1    0x08    /* GPIO1 Output value */
0108 #define GPIO_GPO2EN   0x10    /* GPIO2 Output enable */
0109 #define GPIO_GPO_2    0x20    /* GPIO2 Output value */
0110 #define GPIO_RESERVED 0x40    /* Reserved */
0111 #define GPIO_RSE      0x80    /* Reload serial EEPROM */
0112 
0113 #define AX88772_IPG0_DEFAULT 0x15
0114 #define AX88772_IPG1_DEFAULT 0x0C
0115 #define AX88772_IPG2_DEFAULT 0x12
0116 
0117 static bool
0118 send_cmd (bool input, uint8 cmd, uint16 val, uint16 index,
0119           uint16 len, uint8 *buf)
0120 {
0121   USB_DEV_REQ setup_req;
0122 
0123   setup_req.bmRequestType = (input ? 0x80 : 0x00) | 0x40;
0124   setup_req.bRequest = cmd;
0125   setup_req.wValue = val;
0126   setup_req.wIndex = index;
0127   setup_req.wLength = len;
0128 
0129   {
0130     uint8 *ptr = (uint8 *) &setup_req;
0131     DLOG ("send_cmd : %.02X%.02X_%.02X%.02X_%.02X%.02X_%.02X%.02X",
0132           ptr[0], ptr[1], ptr[2], ptr[3],
0133           ptr[4], ptr[5], ptr[6], ptr[7]);
0134   }
0135 
0136   return usb_control_transfer (ethusbdev, &setup_req, sizeof (USB_DEV_REQ),
0137                                buf, len) == 0;
0138 }
0139 
0140 static inline bool
0141 sw_mii (void)
0142 {
0143   return send_cmd (FALSE, SOFTWARE_MII, 0, 0, 0, NULL);
0144 }
0145 
0146 static inline bool
0147 hw_mii (void)
0148 {
0149   return send_cmd (FALSE, HARDWARE_MII, 0, 0, 0, NULL);
0150 }
0151 
0152 static inline bool
0153 mdio_write (uint16 phy_id, uint16 loc, uint16 val)
0154 {
0155   bool ret;
0156   sw_mii ();
0157   ret = send_cmd (FALSE, PHY_WRITE_REG, phy_id, loc, 2, (uint8 *) &val);
0158   hw_mii ();
0159   return ret;
0160 }
0161 
0162 static inline uint16
0163 mdio_read (uint16 phy_id, uint16 loc)
0164 {
0165   uint16 val;
0166   sw_mii ();
0167   if (!send_cmd (TRUE, PHY_READ_REG, phy_id, loc, 2, (uint8 *) &val))
0168     val = 0;
0169   hw_mii ();
0170   return val;
0171 }
0172 
0173 static uint16
0174 read_rx_ctrl (void)
0175 {
0176   uint16 rx = 0;
0177   if (send_cmd (TRUE, RX_CTRL_READ, 0, 0, 2, (uint8 *) &rx))
0178     return rx;
0179   else
0180     return 0;
0181 }
0182 
0183 static bool
0184 write_rx_ctrl (uint16 rx)
0185 {
0186   return send_cmd (FALSE, RX_CTRL_WRITE, rx, 0, 0, NULL);
0187 }
0188 
0189 static bool
0190 reset (void)
0191 {
0192   uint32 phy_id, phy_reg1, phy_reg2;
0193   uint16 bmcr, medium;
0194 
0195   /* setup GPIO */
0196   if (!send_cmd (FALSE, GPIO_WRITE, GPIO_RSE | GPIO_GPO_2 | GPIO_GPO2EN,
0197                  0, 0, NULL))
0198     goto abort;
0199   delay (5);
0200 
0201   /* setup embedded or external PHY */
0202   if (!send_cmd (TRUE, ETH_PHY_ID, 0, 0, 2, (uint8 *)&phy_id))
0203     goto abort;
0204 
0205   if ((phy_id & 0xE0) == 0xE0) {
0206     /* lower byte is unsupported PHY */
0207     phy_id >>= 8;
0208     if ((phy_id & 0xE0) == 0xE0) {
0209       DLOG ("no supported PHY");
0210       goto abort;
0211     }
0212   }
0213 
0214   phy_id &= 0x1F;               /* mask ID bits */
0215 
0216   DLOG ("phy_id=0x%x", phy_id);
0217 
0218   if (!send_cmd (FALSE, SW_PHY_SELECT,
0219                  (phy_id & 0x1F) == 0x10 ? 1 : 0,
0220                  0, 0, NULL))
0221     goto abort;
0222 
0223   DLOG ("sending SW reset");
0224   /* reset card */
0225   if (!send_cmd (FALSE, SW_RESET, SWRESET_IPPD | SWRESET_PRL, 0, 0, NULL))
0226     goto abort;
0227   delay (150);
0228   if (!send_cmd (FALSE, SW_RESET, SWRESET_CLEAR, 0, 0, NULL))
0229     goto abort;
0230   delay (150);
0231   if (!send_cmd (FALSE, SW_RESET,
0232                  (phy_id & 0x1F) == 0x10 ? SWRESET_IPRL : SWRESET_PRTE,
0233                  0, 0, NULL))
0234     goto abort;
0235   delay (150);
0236 
0237   /* check RX CTRL */
0238   DLOG ("RXCTRL=0x%x", read_rx_ctrl ());
0239   if (!write_rx_ctrl (0x0))
0240     goto abort;
0241   DLOG ("wrote 0x0 -- RXCTRL=0x%x", read_rx_ctrl ());
0242 
0243   /* get ethernet address */
0244   memset (ethaddr, 0, ETH_ADDR_LEN);
0245   if (!send_cmd (TRUE, GET_NODE_ID, 0, 0, ETH_ADDR_LEN, ethaddr))
0246     goto abort;
0247 
0248   DLOG ("ethaddr=%.02X:%.02X:%.02X:%.02X:%.02X:%.02X",
0249         ethaddr[0], ethaddr[1], ethaddr[2], ethaddr[3], ethaddr[4], ethaddr[5]);
0250 
0251   /* get PHY IDENTIFIER (vendor, model) from MII registers */
0252   phy_reg1 = mdio_read (phy_id, MII_PHYSID1);
0253   phy_reg2 = mdio_read (phy_id, MII_PHYSID2);
0254 
0255   DLOG ("MII said PHY IDENTIFIER=0x%x",
0256         ((phy_reg1 & 0xffff) << 16) | (phy_reg2 & 0xffff));
0257 
0258 
0259   /* reset card again */
0260   DLOG ("resending SW reset");
0261   if (!send_cmd (FALSE, SW_RESET, SWRESET_PRL, 0, 0, NULL))
0262     goto abort;
0263   delay (150);
0264   if (!send_cmd (FALSE, SW_RESET, SWRESET_IPRL | SWRESET_PRL, 0, 0, NULL))
0265     goto abort;
0266   delay (150);
0267 
0268   /* init MII */
0269   mdio_write (phy_id, MII_BMCR, BMCR_RESET);
0270   mdio_write (phy_id, MII_ADVERTISE, ADVERTISE_ALL | ADVERTISE_CSMA);
0271 
0272   /* autonegotiation */
0273   bmcr = mdio_read (phy_id, MII_BMCR);
0274   DLOG ("enabling autonegotiation.  BMCR=0x%x", bmcr);
0275   if (bmcr & BMCR_ANENABLE) {
0276     bmcr |= BMCR_ANRESTART;
0277     mdio_write (phy_id, MII_BMCR, bmcr);
0278   } else
0279     goto abort;
0280 
0281   DLOG ("setting medium mode=0x%x", AX88772_MEDIUM_DEFAULT);
0282   /* setup medium mode */
0283   if (!send_cmd (FALSE, MEDIUM_MODE, AX88772_MEDIUM_DEFAULT, 0, 0, NULL))
0284     goto abort;
0285 
0286   /* interpacket gap */
0287   DLOG ("setting IPG");
0288   if (!send_cmd (FALSE, WRITE_IPG,
0289                  AX88772_IPG0_DEFAULT | (AX88772_IPG1_DEFAULT << 8),
0290                  AX88772_IPG2_DEFAULT, 0, NULL))
0291     goto abort;
0292 
0293   DLOG ("accepting broadcasts, starting operation");
0294   /* Accept Broadcasts and Start Operation */
0295   if (!write_rx_ctrl (0x88))       /* AB | SO */
0296     goto abort;
0297 
0298   DLOG ("RXCTRL=0x%x at end of reset", read_rx_ctrl ());
0299 
0300   if (!send_cmd (TRUE, MEDIUM_STATUS, 0, 0, 2, (uint8 *) &medium))
0301     goto abort;
0302   DLOG ("medium status=0x%x at end of reset", medium);
0303 
0304   bmcr = mdio_read (phy_id, MII_BMCR);
0305   DLOG ("BMCR=0x%x at end of reset", bmcr);
0306 
0307   DLOG ("BMSR=0x%x at end of reset", mdio_read (phy_id, MII_BMSR));
0308 
0309   return TRUE;
0310  abort:
0311   DLOG ("reset failed");
0312   return FALSE;
0313 }
0314 
0315 static bool
0316 get_hwaddr (uint8 addr[ETH_ADDR_LEN])
0317 {
0318   int i;
0319   for (i=0; i<ETH_ADDR_LEN; i++)
0320     addr[i] = ethaddr[i];
0321   return TRUE;
0322 }
0323 
0324 static sint
0325 transmit (uint8* buf, sint len)
0326 {
0327   static uint8 frame[MAX_FRAME_SIZE];
0328   sint ret;
0329   uint32 act_len;
0330   uint32 prop_len = ((len ^ 0x0000ffff) << 16) | len;
0331 
0332   memcpy (frame, &prop_len, 4);
0333   memcpy (frame+4, buf, len);
0334 
0335 #ifdef DEBUG_ASIX_DATA
0336   DLOG ("transmitting data len=%d: %.02X %.02X %.02X %.02X", len,
0337         frame[0], frame[1], frame[2], frame[3]);
0338   DLOG ("                         %.02X %.02X %.02X %.02X",
0339         frame[4], frame[5], frame[6], frame[7]);
0340   DLOG ("                         %.02X %.02X %.02X %.02X",
0341         frame[8], frame[9], frame[10], frame[11]);
0342   DLOG ("                         %.02X %.02X %.02X %.02X",
0343         frame[12], frame[13], frame[14], frame[15]);
0344 #endif
0345 
0346   if (usb_bulk_transfer (ethusbdev, data_ept_out, frame, len+4,
0347                          data_maxpkt, DIR_OUT, &act_len) == 0)
0348     ret = act_len;
0349   else
0350     ret = 0;
0351   DLOG ("transmitted %d bytes", act_len);
0352   return ret;
0353 }
0354 
0355 static void
0356 poll (void)
0357 {
0358   uint8 buffer[1600];
0359   uint32 act_len;
0360   if (usb_bulk_transfer (ethusbdev, data_ept_in, buffer, 1514,
0361                          data_maxpkt, DIR_IN, &act_len) == 0) {
0362     if (act_len > 0) {
0363 #ifdef DEBUG_ASIX_DATA
0364       DLOG ("receiving data len=%.04d: %.02X %.02X %.02X %.02X",
0365             act_len, buffer[0], buffer[1], buffer[2], buffer[3]);
0366       DLOG ("                         %.02X %.02X %.02X %.02X",
0367             buffer[4], buffer[5], buffer[6], buffer[7]);
0368       DLOG ("                         %.02X %.02X %.02X %.02X",
0369             buffer[8], buffer[9], buffer[10], buffer[11]);
0370       DLOG ("                         %.02X %.02X %.02X %.02X",
0371             buffer[12], buffer[13], buffer[14], buffer[15]);
0372 #endif
0373       usbnet_ethdev.recv_func (&usbnet_ethdev, buffer+4, act_len-4);
0374     }
0375   }
0376 }
0377 
0378 static void
0379 irq_loop (void)
0380 {
0381   uint32 tick = 0;
0382   DLOG ("irq_loop pid=0x%x", str ());
0383   for (;;) {
0384     poll ();
0385     DLOG ("iteration %d", tick);
0386     tick++;
0387   }
0388 }
0389 
0390 static void
0391 status_loop (void)
0392 {
0393   uint32 tick = 0, act_len;
0394   uint32 status[2];
0395   DLOG ("status_loop pid=0x%x", str ());
0396   for (;;) {
0397     if (usb_bulk_transfer (ethusbdev, status_ept, (uint8 *)&status, 8,
0398                            status_maxpkt, DIR_IN, &act_len) == 0) {
0399       if (act_len > 0) {
0400         DLOG ("status update 0x%.08X %.08X", status[1], status[0]);
0401         if (status[0] & 0x10000)
0402           DLOG ("  primary link UP");
0403         if (status[0] & 0x20000)
0404           DLOG ("  secondary link UP");
0405         if (status[0] & 0x40000)
0406           DLOG ("  Bulk Out Ethernet Frame Length Error");
0407       }
0408     }
0409     DLOG ("status iteration %d", tick);
0410     tick++;
0411     delay (100);
0412   }
0413 }
0414 
0415 
0416 static uint32 irq_stack[1024] ALIGNED(0x1000);
0417 static task_id irq_pid;
0418 
0419 static uint32 status_stack[1024] ALIGNED(0x1000);
0420 static task_id status_pid;
0421 
0422 static bool
0423 probe (USB_DEVICE_INFO *info, USB_CFG_DESC *cfgd, USB_IF_DESC *ifd)
0424 {
0425   uint i;
0426   USB_EPT_DESC *eptd;
0427 
0428   DLOG ("examining 0x%x 0x%x 0x%x",
0429         ifd->bInterfaceClass,
0430         info->devd.idVendor,
0431         info->devd.idProduct);
0432 
0433   if (!(ifd->bInterfaceClass == 0xFF &&
0434         ifd->bInterfaceSubClass == 0xFF &&
0435         ifd->bInterfaceProtocol == 0x00 &&
0436         /* ASIX */
0437         info->devd.idVendor == 0x0b95 &&
0438         /* Cables-to-go ASIX 88772 */
0439         info->devd.idProduct == 0x772a))
0440     return FALSE;
0441 
0442   /* expect endpoints to follow interface */
0443   eptd = (USB_EPT_DESC *) &ifd[1];
0444 
0445   status_ept = data_ept_in = data_ept_out = 0;
0446 
0447   /* 3 endpoints: 1 interrupt, 2 bulk */
0448   for (i=0; i<3; i++) {
0449     if ((eptd->bmAttributes & 0x3) == 0x3) {
0450       /* interrupt endpoint */
0451       status_ept = eptd->bEndpointAddress & 0x7F;
0452       status_maxpkt = eptd->wMaxPacketSize;
0453     } else if ((eptd->bmAttributes & 0x3) == 0x2) {
0454       /* bulk endpoint */
0455       data_maxpkt = eptd->wMaxPacketSize;
0456       if (eptd->bEndpointAddress & 0x80)
0457         data_ept_in = eptd->bEndpointAddress & 0x7F;
0458       else
0459         data_ept_out = eptd->bEndpointAddress & 0x7F;
0460     }
0461     eptd = &eptd[1];
0462   }
0463 
0464   DLOG ("status_ept=%d data_ept_in=%d data_ept_out=%d data_maxpkt=%d",
0465         status_ept, data_ept_in, data_ept_out, data_maxpkt);
0466 
0467   if (!status_ept || !data_ept_in || !data_ept_out)
0468     return FALSE;
0469 
0470   if (usb_set_configuration (info, cfgd->bConfigurationValue) != 0) {
0471     DLOG ("set_configuration: failed");
0472     return FALSE;
0473   }
0474 
0475   ethusbdev = info;
0476 
0477   if (!reset ())
0478     return FALSE;
0479 
0480   /* Register network device with net subsystem */
0481   usbnet_ethdev.recv_func = NULL;
0482   usbnet_ethdev.send_func = transmit;
0483   usbnet_ethdev.get_hwaddr_func = get_hwaddr;
0484   usbnet_ethdev.poll_func = poll;
0485 
0486   if (!net_register_device (&usbnet_ethdev)) {
0487     DLOG ("registration failed");
0488     return FALSE;
0489   }
0490 
0491   irq_pid = start_kernel_thread ((uint) irq_loop, (uint) &irq_stack[1023]);
0492 #if 0
0493   status_pid = start_kernel_thread ((uint) status_loop,
0494                                     (uint) &status_stack[1023]);
0495 #endif
0496 
0497   return TRUE;
0498 }
0499 
0500 static USB_DRIVER asix_driver = {
0501   .probe = probe
0502 };
0503 
0504 extern bool
0505 usb_asix_driver_init (void)
0506 {
0507   DLOG ("init");
0508   return usb_register_driver (&asix_driver);
0509 }
0510 
0511 #include "module/header.h"
0512 
0513 static const struct module_ops mod_ops = {
0514   .init = usb_asix_driver_init
0515 };
0516 
0517 DEF_MODULE (usb___asix, "USB asix network driver", &mod_ops, {"usb", "net___ethernet"});
0518 
0519 
0520 /*
0521  * Local Variables:
0522  * indent-tabs-mode: nil
0523  * mode: C
0524  * c-file-style: "gnu"
0525  * c-basic-offset: 2
0526  * End:
0527  */
0528 
0529 /* vi: set et sw=2 sts=2: */