Print this page
    
7127  remove -Wno-missing-braces from Makefile.uts
    
      
        | Split | 
	Close | 
      
      | Expand all | 
      | Collapse all | 
    
    
          --- old/usr/src/uts/common/io/usb/clients/usbecm/usbecm.c
          +++ new/usr/src/uts/common/io/usb/clients/usbecm/usbecm.c
   1    1  /*
   2    2   * CDDL HEADER START
   3    3   *
   4    4   * The contents of this file are subject to the terms of the
   5    5   * Common Development and Distribution License (the "License").
   6    6   * You may not use this file except in compliance with the License.
   7    7   *
   8    8   * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9    9   * or http://www.opensolaris.org/os/licensing.
  10   10   * See the License for the specific language governing permissions
  11   11   * and limitations under the License.
  12   12   *
  13   13   * When distributing Covered Code, include this CDDL HEADER in each
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  
  22   22  /*
  23   23   * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  24   24   * Use is subject to license terms.
  25   25   */
  26   26  
  27   27  /*
  28   28   * USB Ethernet Control Model
  29   29   *
  30   30   * USB-IF defines three ethernet network related specifications: EEM,
  31   31   * ECM and NCM. This driver focuses specifically on ECM compatible
  32   32   * devices. This kind of devices generally have one pair of bulk
  33   33   * endpoints for in/out packet data and one interrupt endpoint for
  34   34   * device notification.
  35   35   *
  36   36   * Devices which don't report ECM compatibility through descriptors but
  37   37   * implement the ECM functions may also bind to this driver. This driver
  38   38   * will try to find at least a bulk in endpoint and a bulk out endpoint
  39   39   * in this case. If the non-compatible devices use vendor specific data
  40   40   * format, this driver will not function.
  41   41   *
  42   42   * This driver is a normal USBA client driver. It's also a GLDv3 driver,
  43   43   * which provides the necessary interfaces the GLDv3 framework requires.
  44   44   *
  45   45   */
  46   46  
  47   47  #include <sys/types.h>
  48   48  #include <sys/strsun.h>
  49   49  #include <sys/ddi.h>
  50   50  #include <sys/sunddi.h>
  51   51  #include <sys/byteorder.h>
  52   52  #include <sys/usb/usba/usbai_version.h>
  53   53  #include <sys/usb/usba.h>
  54   54  #include <sys/usb/usba/usba_types.h>
  55   55  #include <sys/usb/clients/usbcdc/usb_cdc.h>
  56   56  #include <sys/usb/clients/usbecm/usbecm.h>
  57   57  #include <sys/mac_provider.h>
  58   58  #include <sys/strsubr.h>
  59   59  #include <sys/ethernet.h>
  60   60  #include <sys/mac_ether.h> /* MAC_PLUGIN_IDENT_ETHER */
  61   61  #include <sys/random.h> /* random_get_bytes */
  62   62  #include <sys/sdt.h>    /* sdt */
  63   63  #include <inet/nd.h>
  64   64  
  65   65  /* MAC callbacks */
  66   66  static int      usbecm_m_stat(void *arg, uint_t stat, uint64_t *val);
  67   67  static int      usbecm_m_start(void *arg);
  68   68  static void     usbecm_m_stop(void *arg);
  69   69  static int      usbecm_m_unicst(void *arg, const uint8_t *macaddr);
  70   70  static int      usbecm_m_multicst(void *arg, boolean_t add, const uint8_t *m);
  71   71  static int      usbecm_m_promisc(void *arg, boolean_t on);
  72   72  static void     usbecm_m_ioctl(void *arg, queue_t *wq, mblk_t *mp);
  73   73  static mblk_t   *usbecm_m_tx(void *arg, mblk_t *mp);
  74   74  static int      usbecm_m_getprop(void *arg, const char *pr_name,
  75   75      mac_prop_id_t wldp_pr_num, uint_t wldp_length, void *wldp_buf);
  76   76  static int      usbecm_m_setprop(void *arg, const char *pr_name,
  77   77      mac_prop_id_t wldp_pr_num, uint_t wldp_length, const void *wldp_buf);
  78   78  
  79   79  static int      usbecm_usb_init(usbecm_state_t *ecmp);
  80   80  static int      usbecm_mac_init(usbecm_state_t *ecmp);
  81   81  static int      usbecm_mac_fini(usbecm_state_t *ecmp);
  82   82  
  83   83  
  84   84  /* utils */
  85   85  static void     generate_ether_addr(uint8_t *mac_addr);
  86   86  static int      usbecm_rx_start(usbecm_state_t *ecmp);
  87   87  
  88   88  static void     usbecm_pipe_start_polling(usbecm_state_t *ecmp);
  89   89  static void     usbecm_intr_cb(usb_pipe_handle_t ph, usb_intr_req_t *req);
  90   90  static void     usbecm_intr_ex_cb(usb_pipe_handle_t ph, usb_intr_req_t *req);
  91   91  static void     usbecm_parse_intr_data(usbecm_state_t *ecmp, mblk_t *data);
  92   92  
  93   93  static int      usbecm_reconnect_event_cb(dev_info_t *dip);
  94   94  static int      usbecm_disconnect_event_cb(dev_info_t *dip);
  95   95  
  96   96  static int      usbecm_open_pipes(usbecm_state_t *ecmp);
  97   97  static void     usbecm_close_pipes(usbecm_state_t *ecmp);
  98   98  
  99   99  static int      usbecm_ctrl_read(usbecm_state_t *ecmp, uchar_t request,
 100  100      uint16_t value, mblk_t **data, int len);
 101  101  static int      usbecm_ctrl_write(usbecm_state_t *ecmp, uchar_t request,
 102  102      uint16_t value, mblk_t **data);
 103  103  static int      usbecm_send_data(usbecm_state_t *ecmp, mblk_t *data);
 104  104  static int      usbecm_send_zero_data(usbecm_state_t *ecmp);
 105  105  static int      usbecm_get_statistics(usbecm_state_t *ecmp, uint32_t fs,
 106  106      uint32_t *stat_data);
 107  107  
 108  108  static int      usbecm_create_pm_components(usbecm_state_t *ecmp);
 109  109  static void     usbecm_destroy_pm_components(usbecm_state_t *ecmp);
 110  110  static int      usbecm_power(dev_info_t *dip, int comp, int level);
 111  111  static void     usbecm_pm_set_busy(usbecm_state_t *ecmp);
 112  112  static void     usbecm_pm_set_idle(usbecm_state_t *ecmp);
 113  113  
 114  114  static int      usbecm_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
 115  115  static int      usbecm_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
 116  116  
 117  117  static int      usbecm_suspend(usbecm_state_t *ecmp);
 118  118  static int      usbecm_resume(usbecm_state_t *ecmp);
 119  119  static int      usbecm_restore_device_state(usbecm_state_t *ecmp);
 120  120  static void     usbecm_cleanup(usbecm_state_t *ecmp);
 121  121  
 122  122  /* Driver identification */
 123  123  static char usbecm_ident[] = "usbecm 1.0";
 124  124  
 125  125  /* Global state pointer for managing per-device soft states */
 126  126  void *usbecm_statep;
 127  127  
 128  128  /* print levels */
 129  129  static uint_t   usbecm_errlevel = USB_LOG_L3;
 130  130  static uint_t   usbecm_errmask = 0xffffffff;
 131  131  static uint_t   usbecm_instance_debug = (uint_t)-1;
 132  132  
 133  133  /*
 134  134   * to prevent upper layers packet flood from exhausting system
 135  135   * resources(USBA does not set limitation of requests on a pipe),
 136  136   * we set a upper limit for the transfer queue length.
 137  137   */
 138  138  static  int     usbecm_tx_max = 32;
 139  139  
 140  140  #define SUN_SP_VENDOR_ID        0x0430
 141  141  #define SUN_SP_PRODUCT_ID       0xa4a2
 142  142  
 143  143  static uint8_t  usbecm_broadcast[ETHERADDRL] = {
 144  144          0xff, 0xff, 0xff, 0xff, 0xff, 0xff
 145  145  };
 146  146  
 147  147  static usb_event_t usbecm_events = {
 148  148          usbecm_disconnect_event_cb,
 149  149          usbecm_reconnect_event_cb,
 150  150          NULL, NULL
 151  151  };
 152  152  
 153  153  #define ECM_DS_OP_VALID(op) ((ecmp->ecm_ds_ops) && (ecmp->ecm_ds_ops->op))
 154  154  
 155  155  /*
 156  156   * MAC Call Back entries
 157  157   */
 158  158  static mac_callbacks_t usbecm_m_callbacks = {
 159  159          MC_IOCTL | MC_SETPROP | MC_GETPROP,
 160  160          usbecm_m_stat,          /* Get the value of a statistic */
 161  161          usbecm_m_start,         /* Start the device */
 162  162          usbecm_m_stop,          /* Stop the device */
 163  163          usbecm_m_promisc,       /* Enable or disable promiscuous mode */
 164  164          usbecm_m_multicst,      /* Enable or disable a multicast addr */
 165  165          usbecm_m_unicst,        /* Set the unicast MAC address */
 166  166          usbecm_m_tx,            /* Transmit a packet */
 167  167          NULL,
 168  168          usbecm_m_ioctl,         /* Process an unknown ioctl */
 169  169          NULL,                   /* mc_getcapab */
 170  170          NULL,                   /* mc_open */
 171  171          NULL,                   /* mc_close */
 172  172          usbecm_m_setprop,       /* mc_setprop */
 173  173          usbecm_m_getprop,       /* mc_getprop */
 174  174          NULL
 175  175  };
 176  176  
 177  177  
 178  178  /*
 179  179   *  Module Loading Data & Entry Points
 180  180   *     Can't use DDI_DEFINE_STREAM_OPS, since it does
 181  181   *     not provide devo_power entry.
 182  182   */
 183  183  static struct cb_ops cb_usbecm = {
 184  184          nulldev,                /* cb_open */
 185  185          nulldev,                /* cb_close */
 186  186          nodev,                  /* cb_strategy */
 187  187          nodev,                  /* cb_print */
 188  188          nodev,                  /* cb_dump */
 189  189          nodev,                  /* cb_read */
 190  190          nodev,                  /* cb_write */
 191  191          nodev,                  /* cb_ioctl */
 192  192          nodev,                  /* cb_devmap */
 193  193          nodev,                  /* cb_mmap */
 194  194          nodev,                  /* cb_segmap */
 195  195          nochpoll,               /* cb_chpoll */
 196  196          ddi_prop_op,            /* cb_prop_op */
 197  197          NULL,                   /* cb_stream */
 198  198          D_MP,                   /* cb_flag */
 199  199          CB_REV,                 /* cb_rev */
 200  200          nodev,                  /* cb_aread */
 201  201          nodev,                  /* cb_awrite */
 202  202  };
 203  203  
 204  204  static struct dev_ops usbecm_devops = {
 205  205          DEVO_REV,               /* devo_rev */
 206  206          0,                      /* devo_refcnt */
 207  207          NULL,                   /* devo_getinfo */
 208  208          nulldev,                /* devo_identify */
 209  209          nulldev,                /* devo_probe */
 210  210          usbecm_attach,          /* devo_attach */
 211  211          usbecm_detach,          /* devo_detach */
 212  212          nodev,                  /* devo_reset */
 213  213          &(cb_usbecm),           /* devo_cb_ops */
 214  214          (struct bus_ops *)NULL, /* devo_bus_ops */
 215  215          usbecm_power,           /* devo_power */
  
    | 
      ↓ open down ↓ | 
    215 lines elided | 
    
      ↑ open up ↑ | 
  
 216  216          ddi_quiesce_not_needed  /* devo_quiesce */
 217  217  };
 218  218  
 219  219  static struct modldrv usbecm_modldrv = {
 220  220          &mod_driverops,         /* drv_modops */
 221  221          usbecm_ident,           /* drv_linkinfo */
 222  222          &usbecm_devops          /* drv_dev_ops */
 223  223  };
 224  224  
 225  225  static struct modlinkage usbecm_ml = {
 226      -        MODREV_1,               /* ml_rev */
 227      -        &usbecm_modldrv, NULL   /* ml_linkage */
      226 +        MODREV_1,                       /* ml_rev */
      227 +        { &usbecm_modldrv, NULL }       /* ml_linkage */
 228  228  };
 229  229  
 230  230  
 231  231  /*
 232  232   * Device operations
 233  233   */
 234  234  /*
 235  235   * Binding the driver to a device.
 236  236   *
 237  237   * Concurrency: Until usbecm_attach() returns with success,
 238  238   * the only other entry point that can be executed is getinfo().
 239  239   * Thus no locking here yet.
 240  240   */
 241  241  static int
 242  242  usbecm_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
 243  243  {
 244  244          char strbuf[32];
 245  245          int instance;
 246  246          int err;
 247  247          usbecm_state_t *ecmp = NULL;
 248  248  
 249  249          switch (cmd) {
 250  250          case DDI_ATTACH:
 251  251                  break;
 252  252  
 253  253          case DDI_RESUME:
 254  254                  ecmp = (usbecm_state_t *)ddi_get_soft_state(usbecm_statep,
 255  255                      ddi_get_instance(dip));
 256  256  
 257  257                  (void) usbecm_resume(ecmp);
 258  258  
 259  259                  return (DDI_SUCCESS);
 260  260  
 261  261          default:
 262  262                  return (DDI_FAILURE);
 263  263          }
 264  264  
 265  265          instance = ddi_get_instance(dip);
 266  266  
 267  267          if (ddi_soft_state_zalloc(usbecm_statep, instance) == DDI_SUCCESS) {
 268  268                  ecmp = ddi_get_soft_state(usbecm_statep, instance);
 269  269          }
 270  270          if (ecmp == NULL) {
 271  271                  cmn_err(CE_WARN, "usbecm_attach: fail to get soft state");
 272  272  
 273  273                  return (DDI_FAILURE);
 274  274          }
 275  275  
 276  276          ecmp->ecm_dip = dip;
 277  277  
 278  278          ecmp->ecm_lh = usb_alloc_log_hdl(ecmp->ecm_dip, "usbecm",
 279  279              &usbecm_errlevel, &usbecm_errmask, &usbecm_instance_debug, 0);
 280  280  
 281  281          if (usbecm_usb_init(ecmp) != USB_SUCCESS) {
 282  282                  USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
 283  283                      "usbecm_attach: failed to init usb");
 284  284  
 285  285                  goto fail;
 286  286          }
 287  287  
 288  288          if (ECM_DS_OP_VALID(ecm_ds_init)) {
 289  289                  if (ecmp->ecm_ds_ops->ecm_ds_init(ecmp) != USB_SUCCESS) {
 290  290                          USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
 291  291                              "usbecm_attach: failed to init DS");
 292  292  
 293  293                          goto fail;
 294  294                  }
 295  295          }
 296  296  
 297  297          if (usbecm_mac_init(ecmp) != DDI_SUCCESS) {
 298  298                  USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
 299  299                      "usbecm_attach: failed to init mac");
 300  300  
 301  301                  goto fail;
 302  302          }
 303  303          ecmp->ecm_init_flags |= USBECM_INIT_MAC;
 304  304  
 305  305          /*
 306  306           * Create minor node of type usb_net. Not necessary to create
 307  307           * DDI_NT_NET since it's created in mac_register(). Otherwise,
 308  308           * system will panic.
 309  309           */
 310  310          (void) snprintf(strbuf, sizeof (strbuf), "usbecm%d", instance);
 311  311          err = ddi_create_minor_node(dip, strbuf, S_IFCHR,
 312  312              instance + 1, "usb_net", 0);
 313  313          if (err != DDI_SUCCESS) {
 314  314                  USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
 315  315                      "failed to create minor node");
 316  316  
 317  317                  goto fail;
 318  318          }
 319  319  
 320  320          /* always busy. May change to a more precise PM in future */
 321  321          usbecm_pm_set_busy(ecmp);
 322  322  
 323  323          ddi_report_dev(dip);
 324  324  
 325  325          USB_DPRINTF_L4(PRINT_MASK_ATTA, ecmp->ecm_lh,
 326  326              "usbecm_attach: succeed!");
 327  327  
 328  328          return (DDI_SUCCESS);
 329  329  
 330  330  fail:
 331  331          USB_DPRINTF_L1(PRINT_MASK_ATTA, ecmp->ecm_lh,
 332  332              "usbecm_attach: Attach fail");
 333  333  
 334  334          usbecm_cleanup(ecmp);
 335  335          ddi_prop_remove_all(dip);
 336  336          ddi_soft_state_free(usbecm_statep, instance);
 337  337  
 338  338          return (DDI_FAILURE);
 339  339  
 340  340  }
 341  341  
 342  342  
 343  343  /*
 344  344   * Detach the driver from a device.
 345  345   *
 346  346   * Concurrency: Will be called only after a successful attach
 347  347   * (and not concurrently).
 348  348   */
 349  349  static int
 350  350  usbecm_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
 351  351  {
 352  352          usbecm_state_t *ecmp = NULL;
 353  353          int instance;
 354  354  
 355  355          instance = ddi_get_instance(dip);
 356  356          ecmp = ddi_get_soft_state(usbecm_statep, instance);
 357  357          ASSERT(ecmp != NULL);
 358  358  
 359  359          USB_DPRINTF_L4(PRINT_MASK_ATTA, ecmp->ecm_lh,
 360  360              "usbecm_detach: entry ");
 361  361  
 362  362          switch (cmd) {
 363  363          case DDI_DETACH:
 364  364                  break;
 365  365  
 366  366          case DDI_SUSPEND:
 367  367  
 368  368                  return (usbecm_suspend(ecmp));
 369  369  
 370  370          default:
 371  371                  return (DDI_FAILURE);
 372  372          }
 373  373  
 374  374          usbecm_pm_set_idle(ecmp);
 375  375  
 376  376          if (ECM_DS_OP_VALID(ecm_ds_fini)) {
 377  377                  if (ecmp->ecm_ds_ops->ecm_ds_fini(ecmp) != USB_SUCCESS) {
 378  378                          USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
 379  379                              "usbecm_detach: deinitialize DS fail!");
 380  380  
 381  381                          return (DDI_FAILURE);
 382  382                  }
 383  383          }
 384  384  
 385  385          if (usbecm_mac_fini(ecmp) != 0) {
 386  386  
 387  387                  return (DDI_FAILURE);
 388  388          }
 389  389  
 390  390          USB_DPRINTF_L4(PRINT_MASK_ATTA, ecmp->ecm_lh,
 391  391              "usbecm_detach: exit");
 392  392  
 393  393          usbecm_cleanup(ecmp);
 394  394          ddi_soft_state_free(usbecm_statep, instance);
 395  395  
 396  396          return (DDI_SUCCESS);
 397  397  }
 398  398  
 399  399  
 400  400  /*
 401  401   * Mac Call Back functions
 402  402   */
 403  403  
 404  404  /*
 405  405   * Read device statistic information.
 406  406   */
 407  407  static int
 408  408  usbecm_m_stat(void *arg, uint_t stat, uint64_t *val)
 409  409  {
 410  410          usbecm_state_t *ecmp = (usbecm_state_t *)arg;
 411  411          uint32_t        stats;
 412  412          int             rval;
 413  413          uint32_t        fs;
 414  414  
 415  415          USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
 416  416              "usbecm_m_stat: entry, stat=%d", stat);
 417  417  
 418  418          /*
 419  419           * Some of the stats are MII specific. We try to
 420  420           * resolve all the statistics we understand. If
 421  421           * the usb device can't provide it, return ENOTSUP.
 422  422           */
 423  423          switch (stat) {
 424  424          case MAC_STAT_IFSPEED:
 425  425                  /* return link speed */
 426  426                  mutex_enter(&ecmp->ecm_mutex);
 427  427                  if (ecmp->ecm_stat.es_downspeed) {
 428  428                          *val = ecmp->ecm_stat.es_downspeed;
 429  429                  } else {
 430  430                          *val = 10 * 1000000ull; /* set a default value */
 431  431                  }
 432  432                  mutex_exit(&ecmp->ecm_mutex);
 433  433  
 434  434                  return (0);
 435  435          case ETHER_STAT_LINK_DUPLEX:
 436  436                  *val = LINK_DUPLEX_FULL;
 437  437  
 438  438                  return (0);
 439  439  
 440  440          case ETHER_STAT_SQE_ERRORS:
 441  441                  *val = 0;
 442  442  
 443  443                  return (0);
 444  444  
 445  445          /* Map MAC/Ether stats to ECM statistics */
 446  446          case MAC_STAT_NORCVBUF:
 447  447                  fs = ECM_RCV_NO_BUFFER;
 448  448  
 449  449                  break;
 450  450          case MAC_STAT_NOXMTBUF:
 451  451                  fs = ECM_XMIT_ERROR;
 452  452  
 453  453                  break;
 454  454          case MAC_STAT_IERRORS:
 455  455                  fs = ECM_RCV_ERROR;
 456  456  
 457  457                  break;
 458  458          case MAC_STAT_OERRORS:
 459  459                  fs = ECM_XMIT_ERROR;
 460  460  
 461  461                  break;
 462  462          case MAC_STAT_RBYTES:
 463  463                  fs = ECM_DIRECTED_BYTES_RCV;
 464  464  
 465  465                  break;
 466  466          case MAC_STAT_IPACKETS:
 467  467                  fs = ECM_RCV_OK; /* frames */
 468  468  
 469  469                  break;
 470  470          case MAC_STAT_OBYTES:
 471  471                  fs = ECM_DIRECTED_BYTES_XMIT;
 472  472  
 473  473                  break;
 474  474          case MAC_STAT_OPACKETS:
 475  475                  fs = ECM_XMIT_OK; /* frames */
 476  476  
 477  477                  break;
 478  478          case MAC_STAT_MULTIRCV:
 479  479                  fs = ECM_MULTICAST_FRAMES_RCV;
 480  480  
 481  481                  break;
 482  482          case MAC_STAT_BRDCSTRCV:
 483  483                  fs = ECM_BROADCAST_FRAMES_RCV;
 484  484  
 485  485                  break;
 486  486          case MAC_STAT_MULTIXMT:
 487  487                  fs = ECM_MULTICAST_FRAMES_XMIT;
 488  488  
 489  489                  break;
 490  490          case MAC_STAT_BRDCSTXMT:
 491  491                  fs = ECM_BROADCAST_FRAMES_XMIT;
 492  492  
 493  493                  break;
 494  494          case MAC_STAT_COLLISIONS:
 495  495                  fs = ECM_XMIT_MAX_COLLISIONS;
 496  496  
 497  497                  break;
 498  498          case MAC_STAT_OVERFLOWS:
 499  499                  fs = ECM_RCV_OVERRUN;
 500  500  
 501  501                  break;
 502  502          case MAC_STAT_UNDERFLOWS:
 503  503                  fs = ECM_XMIT_UNDERRUN;
 504  504  
 505  505                  break;
 506  506          case ETHER_STAT_FCS_ERRORS:
 507  507                  fs = ECM_RCV_CRC_ERROR;
 508  508  
 509  509                  break;
 510  510          case ETHER_STAT_ALIGN_ERRORS:
 511  511                  fs = ECM_RCV_ERROR_ALIGNMENT;
 512  512  
 513  513                  break;
 514  514          case ETHER_STAT_DEFER_XMTS:
 515  515                  fs = ECM_XMIT_DEFERRED;
 516  516  
 517  517                  break;
 518  518          case ETHER_STAT_FIRST_COLLISIONS:
 519  519                  fs = ECM_XMIT_ONE_COLLISION;
 520  520  
 521  521                  break;
 522  522          case ETHER_STAT_MULTI_COLLISIONS:
 523  523                  fs = ECM_XMIT_MORE_COLLISIONS;
 524  524  
 525  525                  break;
 526  526          case ETHER_STAT_TX_LATE_COLLISIONS:
 527  527                  fs = ECM_XMIT_LATE_COLLISIONS;
 528  528  
 529  529                  break;
 530  530  
 531  531          default:
 532  532                  return (ENOTSUP);
 533  533          }
 534  534  
 535  535          /*
 536  536           * we need to access device to get required stats,
 537  537           * so check device state first
 538  538           */
 539  539          mutex_enter(&ecmp->ecm_mutex);
 540  540          if (ecmp->ecm_dev_state != USB_DEV_ONLINE) {
 541  541                  USB_DPRINTF_L2(PRINT_MASK_OPS, ecmp->ecm_lh,
 542  542                      "usbecm_m_stat: device not ONLINE");
 543  543  
 544  544                  mutex_exit(&ecmp->ecm_mutex);
 545  545  
 546  546                  return (EIO);
 547  547          }
 548  548          mutex_exit(&ecmp->ecm_mutex);
 549  549  
 550  550          rval = usbecm_get_statistics(ecmp,
 551  551              ECM_STAT_SELECTOR(fs), &stats);
 552  552          if (rval != USB_SUCCESS) {
 553  553                  mutex_enter(&ecmp->ecm_mutex);
 554  554                  switch (stat) {
 555  555                  case MAC_STAT_IERRORS:
 556  556                          *val = ecmp->ecm_stat.es_ierrors;
 557  557  
 558  558                          break;
 559  559                  case MAC_STAT_OERRORS:
 560  560                          *val = ecmp->ecm_stat.es_oerrors;
 561  561  
 562  562                          break;
 563  563                  case MAC_STAT_RBYTES:
 564  564                          *val = ecmp->ecm_stat.es_ibytes;
 565  565  
 566  566                          break;
 567  567                  case MAC_STAT_IPACKETS:
 568  568                          *val = ecmp->ecm_stat.es_ipackets;
 569  569  
 570  570                          break;
 571  571                  case MAC_STAT_OBYTES:
 572  572                          *val = ecmp->ecm_stat.es_obytes;
 573  573  
 574  574                          break;
 575  575                  case MAC_STAT_OPACKETS:
 576  576                          *val = ecmp->ecm_stat.es_opackets;
 577  577  
 578  578                          break;
 579  579                  case MAC_STAT_MULTIRCV:
 580  580                          *val = ecmp->ecm_stat.es_multircv;
 581  581  
 582  582                          break;
 583  583                  case MAC_STAT_MULTIXMT:
 584  584                          *val = ecmp->ecm_stat.es_multixmt;
 585  585  
 586  586                          break;
 587  587                  case MAC_STAT_BRDCSTRCV:
 588  588                          *val = ecmp->ecm_stat.es_brdcstrcv;
 589  589  
 590  590                          break;
 591  591                  case MAC_STAT_BRDCSTXMT:
 592  592                          *val = ecmp->ecm_stat.es_brdcstxmt;
 593  593  
 594  594                          break;
 595  595                  case ETHER_STAT_MACXMT_ERRORS:
 596  596                          *val = ecmp->ecm_stat.es_macxmt_err;
 597  597                          break;
 598  598                  default:
 599  599                          *val = 0;
 600  600  
 601  601                          break;
 602  602                  }
 603  603                  mutex_exit(&ecmp->ecm_mutex);
 604  604          } else {
 605  605                  *val = stats;
 606  606          }
 607  607  
 608  608          USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
 609  609              "usbecm_m_stat: end");
 610  610  
 611  611          return (0);
 612  612  }
 613  613  
 614  614  
 615  615  /*
 616  616   * Start the device:
 617  617   *      - Set proper altsettings of the data interface
 618  618   *      - Open status and data endpoints
 619  619   *      - Start status polling
 620  620   *      - Get bulk-in ep ready to receive data from ethernet
 621  621   *
 622  622   * Concurrency: Presumably fully concurrent, must lock.
 623  623   */
 624  624  static int
 625  625  usbecm_m_start(void *arg)
 626  626  {
 627  627          usbecm_state_t *ecmp = (usbecm_state_t *)arg;
 628  628          int rval;
 629  629  
 630  630          USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
 631  631              "usbecm_m_start: entry");
 632  632  
 633  633          (void) usb_serialize_access(ecmp->ecm_ser_acc, USB_WAIT, 0);
 634  634          mutex_enter(&ecmp->ecm_mutex);
 635  635          if (ecmp->ecm_dev_state != USB_DEV_ONLINE) {
 636  636                  USB_DPRINTF_L2(PRINT_MASK_OPS, ecmp->ecm_lh,
 637  637                      "usbecm_m_start: device not online");
 638  638                  rval = ENODEV;
 639  639                  mutex_exit(&ecmp->ecm_mutex);
 640  640  
 641  641                  goto fail;
 642  642          }
 643  643          mutex_exit(&ecmp->ecm_mutex);
 644  644  
 645  645          if (usbecm_open_pipes(ecmp) != USB_SUCCESS) {
 646  646                  USB_DPRINTF_L2(PRINT_MASK_OPS, ecmp->ecm_lh,
 647  647                      "usbecm_m_start: open pipes fail");
 648  648                  rval = EIO;
 649  649  
 650  650                  goto fail;
 651  651          }
 652  652  
 653  653          mutex_enter(&ecmp->ecm_mutex);
 654  654          if (usbecm_rx_start(ecmp) != USB_SUCCESS) {
 655  655                  USB_DPRINTF_L2(PRINT_MASK_OPS, ecmp->ecm_lh,
 656  656                      "usbecm_m_start: fail to start_rx");
 657  657                  mutex_exit(&ecmp->ecm_mutex);
 658  658                  rval = EIO;
 659  659  
 660  660                  goto fail;
 661  661          }
 662  662          ecmp->ecm_mac_state = USBECM_MAC_STARTED;
 663  663          mutex_exit(&ecmp->ecm_mutex);
 664  664  
 665  665          /* set the device to receive all multicast/broadcast pkts */
 666  666          rval = usbecm_ctrl_write(ecmp, CDC_ECM_SET_ETH_PKT_FLT,
 667  667              CDC_ECM_PKT_TYPE_DIRECTED | CDC_ECM_PKT_TYPE_ALL_MCAST |
 668  668              CDC_ECM_PKT_TYPE_BCAST, NULL);
 669  669          if (rval != USB_SUCCESS) {
 670  670                  USB_DPRINTF_L3(PRINT_MASK_OPS, ecmp->ecm_lh,
 671  671                      "usbecm_m_start: set packet filters fail,"
 672  672                      " rval=%d, continue", rval);
 673  673          }
 674  674  
 675  675          if (ECM_DS_OP_VALID(ecm_ds_start)) {
 676  676                  if (ecmp->ecm_ds_ops->ecm_ds_start(ecmp) != USB_SUCCESS) {
 677  677                          USB_DPRINTF_L2(PRINT_MASK_OPS, ecmp->ecm_lh,
 678  678                              "usbecm_m_start: Can't start hardware");
 679  679  
 680  680                          goto fail;
 681  681                  }
 682  682          }
 683  683  
 684  684          usb_release_access(ecmp->ecm_ser_acc);
 685  685  
 686  686          USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
 687  687              "usbecm_m_start: end");
 688  688  
 689  689          /*
 690  690           * To mark the link as RUNNING.
 691  691           *
 692  692           * ECM spec doesn't provide a way for host to get the status
 693  693           * of the physical link initiatively. Only the device can
 694  694           * report the link state through interrupt endpoints.
 695  695           */
 696  696          mac_link_update(ecmp->ecm_mh, LINK_STATE_UP);
 697  697          mutex_enter(&ecmp->ecm_mutex);
 698  698          ecmp->ecm_stat.es_linkstate = LINK_STATE_UP;
 699  699          mutex_exit(&ecmp->ecm_mutex);
 700  700  
 701  701          return (DDI_SUCCESS);
 702  702  fail:
 703  703          usb_release_access(ecmp->ecm_ser_acc);
 704  704  
 705  705          return (rval);
 706  706  }
 707  707  
 708  708  /*
 709  709   * Stop the device.
 710  710   */
 711  711  static void
 712  712  usbecm_m_stop(void *arg)
 713  713  {
 714  714          usbecm_state_t *ecmp = (usbecm_state_t *)arg;
 715  715  
 716  716          USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
 717  717              "usbecm_m_stop: entry");
 718  718  
 719  719          (void) usb_serialize_access(ecmp->ecm_ser_acc, USB_WAIT, 0);
 720  720          if (ECM_DS_OP_VALID(ecm_ds_stop)) {
 721  721                  if (ecmp->ecm_ds_ops->ecm_ds_stop(ecmp) != USB_SUCCESS) {
 722  722                          USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
 723  723                              "usbecm_m_stop: fail to stop hardware");
 724  724                  }
 725  725          }
 726  726  
 727  727          usbecm_close_pipes(ecmp);
 728  728          usb_release_access(ecmp->ecm_ser_acc);
 729  729  
 730  730          mutex_enter(&ecmp->ecm_mutex);
 731  731          ecmp->ecm_mac_state = USBECM_MAC_STOPPED;
 732  732          mutex_exit(&ecmp->ecm_mutex);
 733  733  
 734  734          mac_link_update(ecmp->ecm_mh, LINK_STATE_DOWN);
 735  735          mutex_enter(&ecmp->ecm_mutex);
 736  736          ecmp->ecm_stat.es_linkstate = LINK_STATE_DOWN;
 737  737          mutex_exit(&ecmp->ecm_mutex);
 738  738  
 739  739          USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
 740  740              "usbecm_m_stop: end");
 741  741  }
 742  742  
 743  743  /*
 744  744   * Change the MAC address of the device.
 745  745   */
 746  746  /*ARGSUSED*/
 747  747  static int
 748  748  usbecm_m_unicst(void *arg, const uint8_t *macaddr)
 749  749  {
 750  750          usbecm_state_t *ecmp = (usbecm_state_t *)arg;
 751  751          uint16_t        filter;
 752  752          int             rval;
 753  753  
 754  754          USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
 755  755              "usbecm_m_unicst: entry");
 756  756  
 757  757          /*
 758  758           * The device doesn't support to set a different MAC addr.
 759  759           * Hence, it's not necessary to stop the device first if
 760  760           * the mac addresses are identical. And we just set unicast
 761  761           * filter only.
 762  762           */
 763  763          if (bcmp(macaddr, ecmp->ecm_srcaddr, ETHERADDRL) != 0) {
 764  764                  USB_DPRINTF_L3(PRINT_MASK_OPS, ecmp->ecm_lh,
 765  765                      "usbecm_m_unicst: not supported to set a"
 766  766                      " different MAC addr");
 767  767  
 768  768                  return (DDI_FAILURE);
 769  769          }
 770  770          mutex_enter(&ecmp->ecm_mutex);
 771  771          filter = ecmp->ecm_pkt_flt |= CDC_ECM_PKT_TYPE_DIRECTED;
 772  772          mutex_exit(&ecmp->ecm_mutex);
 773  773  
 774  774          (void) usb_serialize_access(ecmp->ecm_ser_acc, USB_WAIT, 0);
 775  775          rval = usbecm_ctrl_write(ecmp, CDC_ECM_SET_ETH_PKT_FLT,
 776  776              filter, NULL);
 777  777          usb_release_access(ecmp->ecm_ser_acc);
 778  778  
 779  779          USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
 780  780              "usbecm_m_unicst: rval = %d", rval);
 781  781  
 782  782          /* some devices may not support this request, we just return success */
 783  783          return (DDI_SUCCESS);
 784  784  }
 785  785  
 786  786  /*
 787  787   * Enable/disable multicast.
 788  788   */
 789  789  /*ARGSUSED*/
 790  790  static int
 791  791  usbecm_m_multicst(void *arg, boolean_t add, const uint8_t *m)
 792  792  {
 793  793          usbecm_state_t *ecmp = (usbecm_state_t *)arg;
 794  794          uint16_t        filter;
 795  795          int     rval = 0;
 796  796  
 797  797          USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
 798  798              "usbecm_m_multicst: entry");
 799  799          mutex_enter(&ecmp->ecm_mutex);
 800  800  
 801  801          /*
 802  802           * To simplify the implementation, we support switching
 803  803           * all multicast on/off feature only
 804  804           */
 805  805          if (add == B_TRUE) {
 806  806                  ecmp->ecm_pkt_flt |= CDC_ECM_PKT_TYPE_ALL_MCAST;
 807  807          } else {
 808  808                  ecmp->ecm_pkt_flt &= ~CDC_ECM_PKT_TYPE_ALL_MCAST;
 809  809          }
 810  810          filter = ecmp->ecm_pkt_flt;
 811  811          mutex_exit(&ecmp->ecm_mutex);
 812  812  
 813  813          (void) usb_serialize_access(ecmp->ecm_ser_acc, USB_WAIT, 0);
 814  814          if (ecmp->ecm_compatibility &&
 815  815              (ecmp->ecm_desc.wNumberMCFilters & 0x7F)) {
 816  816          /* Device supports SetEthernetMulticastFilters request */
 817  817                  rval = usbecm_ctrl_write(ecmp, CDC_ECM_SET_ETH_PKT_FLT,
 818  818                      filter, NULL);
 819  819                  USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
 820  820                      "usbecm_m_multicst: rval = %d", rval);
 821  821          }
 822  822          usb_release_access(ecmp->ecm_ser_acc);
 823  823  
 824  824          /* some devices may not support this request, we just return success */
 825  825          return (DDI_SUCCESS);
 826  826  }
 827  827  
 828  828  /*
 829  829   * Enable/disable promiscuous mode.
 830  830   */
 831  831  static int
 832  832  usbecm_m_promisc(void *arg, boolean_t on)
 833  833  {
 834  834          usbecm_state_t *ecmp = (usbecm_state_t *)arg;
 835  835          uint16_t        filter;
 836  836          int             rval;
 837  837  
 838  838          USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
 839  839              "usbecm_m_promisc: entry");
 840  840  
 841  841          mutex_enter(&ecmp->ecm_mutex);
 842  842          if (ecmp->ecm_dev_state != USB_DEV_ONLINE) {
 843  843                  USB_DPRINTF_L2(PRINT_MASK_OPS, ecmp->ecm_lh,
 844  844                      "usbecm_m_promisc: device not ONLINE");
 845  845                  mutex_exit(&ecmp->ecm_mutex);
 846  846  
 847  847                  return (DDI_FAILURE);
 848  848          }
 849  849  
 850  850  
 851  851          if (on == B_TRUE) {
 852  852                  ecmp->ecm_pkt_flt |= CDC_ECM_PKT_TYPE_PROMISC;
 853  853          } else {
 854  854                  ecmp->ecm_pkt_flt &= ~CDC_ECM_PKT_TYPE_PROMISC;
 855  855          }
 856  856          filter = ecmp->ecm_pkt_flt;
 857  857          mutex_exit(&ecmp->ecm_mutex);
 858  858  
 859  859          (void) usb_serialize_access(ecmp->ecm_ser_acc, USB_WAIT, 0);
 860  860          rval = usbecm_ctrl_write(ecmp, CDC_ECM_SET_ETH_PKT_FLT,
 861  861              filter, NULL);
 862  862          usb_release_access(ecmp->ecm_ser_acc);
 863  863  
 864  864          USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
 865  865              "usbecm_m_promisc: rval=%d", rval);
 866  866  
 867  867          /*
 868  868           * devices may not support this request, we just
 869  869           * return success to let upper layer to do further
 870  870           * operation.
 871  871           */
 872  872          return (DDI_SUCCESS);
 873  873  }
 874  874  
 875  875  /*
 876  876   * IOCTL request: Does not do anything. Will be enhanced
 877  877   *      in future.
 878  878   */
 879  879  static void
 880  880  usbecm_m_ioctl(void *arg, queue_t *wq, mblk_t *mp)
 881  881  {
 882  882          usbecm_state_t *ecmp = (usbecm_state_t *)arg;
 883  883          struct iocblk   *iocp;
 884  884          int cmd;
 885  885  
 886  886          USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
 887  887              "usbecm_m_ioctl: entry");
 888  888  
 889  889          mutex_enter(&ecmp->ecm_mutex);
 890  890          if (ecmp->ecm_dev_state != USB_DEV_ONLINE) {
 891  891                  USB_DPRINTF_L2(PRINT_MASK_OPS, ecmp->ecm_lh,
 892  892                      "usbecm_m_ioctl: device not ONLINE");
 893  893                  mutex_exit(&ecmp->ecm_mutex);
 894  894  
 895  895                  miocnak(wq, mp, 0, EIO);
 896  896  
 897  897                  return;
 898  898          }
 899  899          mutex_exit(&ecmp->ecm_mutex);
 900  900  
 901  901          iocp = (void *)mp->b_rptr;
 902  902          iocp->ioc_error = 0;
 903  903          cmd = iocp->ioc_cmd;
 904  904  
 905  905          (void) usb_serialize_access(ecmp->ecm_ser_acc, USB_WAIT, 0);
 906  906  
 907  907          switch (cmd) {
 908  908          default:
 909  909                  USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
 910  910                      "unknown cmd 0x%x", cmd);
 911  911                  usb_release_access(ecmp->ecm_ser_acc);
 912  912                  miocnak(wq, mp, 0, EINVAL);
 913  913  
 914  914                  return;
 915  915          }
 916  916  }
 917  917  
 918  918  /*
 919  919   * callback functions for get/set properties
 920  920   *      Does not do anything. Will be enhanced to
 921  921   *      support set/get properties in future.
 922  922   */
 923  923  /*ARGSUSED*/
 924  924  static int
 925  925  usbecm_m_setprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
 926  926      uint_t wldp_length, const void *wldp_buf)
 927  927  {
 928  928          usbecm_state_t *ecmp = (usbecm_state_t *)arg;
 929  929          int err = ENOTSUP;
 930  930  
 931  931          USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
 932  932              "usbecm_m_setprop: entry");
 933  933  
 934  934          return (err);
 935  935  }
 936  936  
 937  937  /*ARGSUSED*/
 938  938  static int usbecm_m_getprop(void *arg, const char *pr_name,
 939  939      mac_prop_id_t wldp_pr_num, uint_t wldp_length, void *wldp_buf)
 940  940  {
 941  941          usbecm_state_t *ecmp = (usbecm_state_t *)arg;
 942  942          int err = ENOTSUP;
 943  943  
 944  944          USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
 945  945              "usbecm_m_getprop: entry");
 946  946  
 947  947          mutex_enter(&ecmp->ecm_mutex);
 948  948          if (ecmp->ecm_dev_state != USB_DEV_ONLINE) {
 949  949                  mutex_exit(&ecmp->ecm_mutex);
 950  950  
 951  951                  return (EIO);
 952  952          }
 953  953          mutex_exit(&ecmp->ecm_mutex);
 954  954  
 955  955          return (err);
 956  956  }
 957  957  
 958  958  /*
 959  959   * Transmit a data frame.
 960  960   */
 961  961  static mblk_t *
 962  962  usbecm_m_tx(void *arg, mblk_t *mp)
 963  963  {
 964  964          usbecm_state_t *ecmp = (usbecm_state_t *)arg;
 965  965          mblk_t *next;
 966  966          int count = 0;
 967  967  
 968  968          ASSERT(mp != NULL);
 969  969  
 970  970          USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
 971  971              "usbecm_m_tx: entry");
 972  972  
 973  973          mutex_enter(&ecmp->ecm_mutex);
 974  974          if (ecmp->ecm_dev_state != USB_DEV_ONLINE) {
 975  975                  USB_DPRINTF_L2(PRINT_MASK_OPS, ecmp->ecm_lh,
 976  976                      "usbecm_m_tx: device not ONLINE");
 977  977                  mutex_exit(&ecmp->ecm_mutex);
 978  978  
 979  979                  return (mp);
 980  980          }
 981  981          mutex_exit(&ecmp->ecm_mutex);
 982  982  
 983  983          (void) usb_serialize_access(ecmp->ecm_ser_acc, USB_WAIT, 0);
 984  984  
 985  985          /*
 986  986           * To make use of the device maximum capability,
 987  987           * concatenate msg blocks in a msg to ETHERMAX length.
 988  988           */
 989  989          while (mp != NULL) {
 990  990                  next = mp->b_next;
 991  991                  mp->b_next = NULL;
 992  992  
 993  993                  if (usbecm_send_data(ecmp, mp) != DDI_SUCCESS) {
 994  994                          USB_DPRINTF_L3(PRINT_MASK_OPS, ecmp->ecm_lh,
 995  995                              "usbecm_m_tx: send data fail");
 996  996  
 997  997                          /* failure statistics */
 998  998                          mutex_enter(&ecmp->ecm_mutex);
 999  999                          ecmp->ecm_stat.es_oerrors++;
1000 1000                          mutex_exit(&ecmp->ecm_mutex);
1001 1001  
1002 1002                          mp->b_next = next;
1003 1003  
1004 1004                          break;
1005 1005                  }
1006 1006  
1007 1007                  /*
1008 1008                   * To make it simple, we count all packets, no matter
1009 1009                   * the device supports ethernet statistics or not.
1010 1010                   */
1011 1011                  mutex_enter(&ecmp->ecm_mutex);
1012 1012                  ecmp->ecm_stat.es_opackets++;
1013 1013                  ecmp->ecm_stat.es_obytes += MBLKL(mp);
1014 1014                  mutex_exit(&ecmp->ecm_mutex);
1015 1015  
1016 1016                  freemsg(mp); /* free this msg upon success */
1017 1017  
1018 1018                  mp = next;
1019 1019                  USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
1020 1020                      "usbecm_m_tx: %d msgs processed", ++count);
1021 1021          }
1022 1022  
1023 1023          usb_release_access(ecmp->ecm_ser_acc);
1024 1024  
1025 1025          return (mp);
1026 1026  }
1027 1027  
1028 1028  /*
1029 1029   * usbecm_bulkin_cb:
1030 1030   *      Bulk In regular and exeception callback;
1031 1031   *      USBA framework will call this callback
1032 1032   *      after deal with bulkin request.
1033 1033   */
1034 1034  /*ARGSUSED*/
1035 1035  static void
1036 1036  usbecm_bulkin_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
1037 1037  {
1038 1038          usbecm_state_t  *ecmp = (usbecm_state_t *)req->bulk_client_private;
1039 1039          mblk_t          *data, *mp;
1040 1040          int             data_len;
1041 1041          int             max_pkt_size = ecmp->ecm_bulkin_sz;
1042 1042  
1043 1043          data = req->bulk_data;
1044 1044          data_len = (data) ? MBLKL(data) : 0;
1045 1045  
1046 1046          ASSERT(data->b_cont == NULL);
1047 1047  
1048 1048          mutex_enter(&ecmp->ecm_mutex);
1049 1049  
1050 1050          USB_DPRINTF_L4(PRINT_MASK_CB, ecmp->ecm_lh,
1051 1051              "usbecm_bulkin_cb: state=%d, len=%d", ecmp->ecm_bulkin_state,
1052 1052              data_len);
1053 1053  
1054 1054          /*
1055 1055           * may receive a zero length packet according
1056 1056           * to USB short packet semantics
1057 1057           */
1058 1058          if ((ecmp->ecm_dev_state == USB_DEV_ONLINE) &&
1059 1059              (req->bulk_completion_reason == USB_CR_OK)) {
1060 1060                  if (data_len) {
1061 1061                          if (ecmp->ecm_rcv_queue == NULL) {
1062 1062                                  ecmp->ecm_rcv_queue = data;
1063 1063                          } else {
1064 1064                                  if ((msgsize(ecmp->ecm_rcv_queue) + data_len)
1065 1065                                      > ETHERMAX) {
1066 1066                                  /*
1067 1067                                   * Exceed the ethernet maximum length, we think
1068 1068                                   * something is wrong with this frame and hence
1069 1069                                   * free older data. Accept new data instead.
1070 1070                                   */
1071 1071                                          freemsg(ecmp->ecm_rcv_queue);
1072 1072                                          ecmp->ecm_rcv_queue = data;
1073 1073                                  } else {
1074 1074                                          linkb(ecmp->ecm_rcv_queue, data);
1075 1075                                  }
1076 1076                          }
1077 1077                  } else {
1078 1078                  /*
1079 1079                   * Do not put zero length packet to receive queue.
1080 1080                   * Otherwise, msgpullup will dupmsg() a zero length
1081 1081                   * mblk, which will cause memleaks.
1082 1082                   */
1083 1083                          freemsg(data);
1084 1084                  }
1085 1085  
1086 1086                  /*
1087 1087                   * ECM V1.2, section 3.3.1, a short(including zero length)
1088 1088                   * packet signifies end of frame. We can submit this frame
1089 1089                   * to upper layer now.
1090 1090                   */
1091 1091                  if ((data_len < max_pkt_size) &&
1092 1092                      (msgsize(ecmp->ecm_rcv_queue) > 0)) {
1093 1093                          mp = msgpullup(ecmp->ecm_rcv_queue, -1);
1094 1094                          freemsg(ecmp->ecm_rcv_queue);
1095 1095                          ecmp->ecm_rcv_queue = NULL;
1096 1096  
1097 1097                          ecmp->ecm_stat.es_ipackets++;
1098 1098                          ecmp->ecm_stat.es_ibytes += msgsize(mp);
1099 1099                          if (mp && (mp->b_rptr[0] & 0x01)) {
1100 1100                                  if (bcmp(mp->b_rptr, usbecm_broadcast,
1101 1101                                      ETHERADDRL) != 0) {
1102 1102                                          ecmp->ecm_stat.es_multircv++;
1103 1103                                  } else {
1104 1104                                          ecmp->ecm_stat.es_brdcstrcv++;
1105 1105                                  }
1106 1106                          }
1107 1107  
1108 1108                          if (mp) {
1109 1109                                  mutex_exit(&ecmp->ecm_mutex);
1110 1110                                  mac_rx(ecmp->ecm_mh, NULL, mp);
1111 1111                                  mutex_enter(&ecmp->ecm_mutex);
1112 1112                          }
1113 1113                  }
1114 1114  
1115 1115                  /* prevent USBA from freeing data along with the request */
1116 1116                  req->bulk_data = NULL;
1117 1117          } else if (req->bulk_completion_reason != USB_CR_OK) {
1118 1118                  ecmp->ecm_stat.es_ierrors++;
1119 1119          }
1120 1120          mutex_exit(&ecmp->ecm_mutex);
1121 1121  
1122 1122          usb_free_bulk_req(req);
1123 1123  
1124 1124          /* receive more */
1125 1125          mutex_enter(&ecmp->ecm_mutex);
1126 1126          if (((ecmp->ecm_bulkin_state == USBECM_PIPE_BUSY) ||
1127 1127              (ecmp->ecm_bulkin_state == USBECM_PIPE_IDLE)) &&
1128 1128              (ecmp->ecm_dev_state == USB_DEV_ONLINE)) {
1129 1129                  if (usbecm_rx_start(ecmp) != USB_SUCCESS) {
1130 1130                          USB_DPRINTF_L2(PRINT_MASK_CB, ecmp->ecm_lh,
1131 1131                              "usbecm_bulkin_cb: restart rx fail "
1132 1132                              "ecmp_state = %d", ecmp->ecm_bulkin_state);
1133 1133                  }
1134 1134          } else if (ecmp->ecm_bulkin_state == USBECM_PIPE_BUSY) {
1135 1135                  ecmp->ecm_bulkin_state = USBECM_PIPE_IDLE;
1136 1136          }
1137 1137          mutex_exit(&ecmp->ecm_mutex);
1138 1138  }
1139 1139  
1140 1140  /*
1141 1141   * usbsecm_rx_start:
1142 1142   *      start data receipt
1143 1143   */
1144 1144  static int
1145 1145  usbecm_rx_start(usbecm_state_t *ecmp)
1146 1146  {
1147 1147          usb_bulk_req_t  *br;
1148 1148          int             rval = USB_FAILURE;
1149 1149          int             data_len;
1150 1150  
1151 1151          ASSERT(mutex_owned(&ecmp->ecm_mutex));
1152 1152  
1153 1153          DTRACE_PROBE2(usbecm_rx__start, int, ecmp->ecm_xfer_sz,
1154 1154              int, ecmp->ecm_bulkin_sz);
1155 1155  
1156 1156          ecmp->ecm_bulkin_state = USBECM_PIPE_BUSY;
1157 1157          data_len = ecmp->ecm_bulkin_sz;
1158 1158  
1159 1159          mutex_exit(&ecmp->ecm_mutex);
1160 1160          br = usb_alloc_bulk_req(ecmp->ecm_dip, data_len, USB_FLAGS_SLEEP);
1161 1161          if (br == NULL) {
1162 1162                  USB_DPRINTF_L2(PRINT_MASK_CB, ecmp->ecm_lh,
1163 1163                      "usbsecm_rx_start: allocate bulk request failed");
1164 1164  
1165 1165                  mutex_enter(&ecmp->ecm_mutex);
1166 1166  
1167 1167                  return (USB_FAILURE);
1168 1168          }
1169 1169          /* initialize bulk in request. */
1170 1170          br->bulk_len = data_len;
1171 1171          br->bulk_timeout = 0;
1172 1172          br->bulk_cb = usbecm_bulkin_cb;
1173 1173          br->bulk_exc_cb = usbecm_bulkin_cb;
1174 1174          br->bulk_client_private = (usb_opaque_t)ecmp;
1175 1175          br->bulk_attributes = USB_ATTRS_AUTOCLEARING
1176 1176              | USB_ATTRS_SHORT_XFER_OK;
1177 1177  
1178 1178          rval = usb_pipe_bulk_xfer(ecmp->ecm_bulkin_ph, br, 0);
1179 1179          mutex_enter(&ecmp->ecm_mutex);
1180 1180          if (rval != USB_SUCCESS) {
1181 1181                  USB_DPRINTF_L2(PRINT_MASK_CB, ecmp->ecm_lh,
1182 1182                      "usbsecm_rx_start: bulk transfer failed %d", rval);
1183 1183                  usb_free_bulk_req(br);
1184 1184                  ecmp->ecm_bulkin_state = USBECM_PIPE_IDLE;
1185 1185          }
1186 1186  
1187 1187          return (rval);
1188 1188  }
1189 1189  
1190 1190  /*
1191 1191   * usbecm_bulkout_cb:
1192 1192   *      Bulk Out regular and exeception callback;
1193 1193   *      USBA framework will call this callback function
1194 1194   *      after deal with bulkout request.
1195 1195   */
1196 1196  /*ARGSUSED*/
1197 1197  static void
1198 1198  usbecm_bulkout_cb(usb_pipe_handle_t pipe, usb_bulk_req_t *req)
1199 1199  {
1200 1200          usbecm_state_t *ecmp = (usbecm_state_t *)req->bulk_client_private;
1201 1201          int             data_len;
1202 1202          boolean_t       need_update = B_FALSE;
1203 1203  
1204 1204          data_len = (req->bulk_data) ? MBLKL(req->bulk_data) : 0;
1205 1205  
1206 1206          USB_DPRINTF_L4(PRINT_MASK_CB, ecmp->ecm_lh,
1207 1207              "usbecm_bulkout_cb: data_len = %d, cr=%d", data_len,
1208 1208              req->bulk_completion_reason);
1209 1209  
1210 1210          mutex_enter(&ecmp->ecm_mutex);
1211 1211          if ((data_len > 0) && (ecmp->ecm_tx_cnt > 0)) {
1212 1212                  if (ecmp->ecm_tx_cnt == usbecm_tx_max) {
1213 1213                          need_update = B_TRUE;
1214 1214                  }
1215 1215                  ecmp->ecm_tx_cnt--;
1216 1216          }
1217 1217          mutex_exit(&ecmp->ecm_mutex);
1218 1218  
1219 1219          if (req->bulk_completion_reason && (data_len > 0)) {
1220 1220                  mutex_enter(&ecmp->ecm_mutex);
1221 1221                  ecmp->ecm_stat.es_oerrors++;
1222 1222                  mutex_exit(&ecmp->ecm_mutex);
1223 1223  
1224 1224                  need_update = B_TRUE;
1225 1225          }
1226 1226  
1227 1227          /*
1228 1228           * notify MAC layer to retransfer the failed packet
1229 1229           * Or notity MAC that we have more buffer now.
1230 1230           */
1231 1231          if (need_update) {
1232 1232                  mac_tx_update(ecmp->ecm_mh);
1233 1233          }
1234 1234  
1235 1235          usb_free_bulk_req(req);
1236 1236  }
1237 1237  
1238 1238  static int
1239 1239  usbecm_send_data(usbecm_state_t *ecmp, mblk_t *data)
1240 1240  {
1241 1241          usb_bulk_req_t  *br;
1242 1242          int             rval = USB_FAILURE;
1243 1243          int             data_len = MBLKL(data);
1244 1244          int             max_pkt_size;
1245 1245          mblk_t          *new_data = NULL;
1246 1246          int             new_data_len = 0;
1247 1247  
1248 1248          USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
1249 1249              "usbecm_send_data: length = %d, total len=%d",
1250 1250              data_len, (int)msgdsize(data));
1251 1251  
1252 1252          mutex_enter(&ecmp->ecm_mutex);
1253 1253          if (ecmp->ecm_tx_cnt >= usbecm_tx_max) {
1254 1254                  USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
1255 1255                      "usbecm_send_data: (%d) exceeds TX max queue length",
1256 1256                      ecmp->ecm_tx_cnt);
1257 1257                  mutex_exit(&ecmp->ecm_mutex);
1258 1258  
1259 1259                  return (USB_FAILURE);
1260 1260          }
1261 1261          mutex_exit(&ecmp->ecm_mutex);
1262 1262  
1263 1263          data_len = msgsize(data);
1264 1264          if (data_len > ETHERMAX) {
1265 1265                  mutex_enter(&ecmp->ecm_mutex);
1266 1266                  ecmp->ecm_stat.es_macxmt_err++;
1267 1267                  mutex_exit(&ecmp->ecm_mutex);
1268 1268  
1269 1269                  USB_DPRINTF_L2(PRINT_MASK_OPS, ecmp->ecm_lh,
1270 1270                      "usbecm_send_data: packet too long, %d", data_len);
1271 1271  
1272 1272                  return (USB_FAILURE);
1273 1273          }
1274 1274  
1275 1275          if (data_len < ETHERMIN) {
1276 1276                  mblk_t *tmp;
1277 1277  
1278 1278                  USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
1279 1279                      "usbecm_send_data: short packet, padding to ETHERMIN");
1280 1280  
1281 1281                  new_data_len = ETHERMIN;
1282 1282                  if ((new_data = allocb(new_data_len, 0)) == NULL) {
1283 1283                          USB_DPRINTF_L2(PRINT_MASK_OPS, ecmp->ecm_lh,
1284 1284                              "usbecm_send_data: fail to allocb");
1285 1285  
1286 1286                          return (USB_FAILURE);
1287 1287                  }
1288 1288                  bzero(new_data->b_wptr, new_data_len);
1289 1289                  for (tmp = data; tmp != NULL; tmp = tmp->b_cont) {
1290 1290                          bcopy(tmp->b_rptr, new_data->b_wptr, MBLKL(tmp));
1291 1291                          new_data->b_wptr += MBLKL(tmp);
1292 1292                  }
1293 1293  
1294 1294                  new_data->b_wptr = new_data->b_rptr + new_data_len;
1295 1295          }
1296 1296  
1297 1297          br = usb_alloc_bulk_req(ecmp->ecm_dip, 0, USB_FLAGS_SLEEP);
1298 1298          if (br == NULL) {
1299 1299                  USB_DPRINTF_L2(PRINT_MASK_OPS, ecmp->ecm_lh,
1300 1300                      "usbecm_send_data: alloc req failed.");
1301 1301  
1302 1302                  return (USB_FAILURE);
1303 1303          }
1304 1304  
1305 1305          /* initialize the bulk out request */
1306 1306          if (new_data) {
1307 1307                  br->bulk_data = msgpullup(new_data, -1); /* msg allocated! */
1308 1308                  br->bulk_len = new_data_len;
1309 1309          } else {
1310 1310                  br->bulk_data = msgpullup(data, -1); /* msg allocated! */
1311 1311                  br->bulk_len = data_len;
1312 1312          }
1313 1313  
1314 1314          USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
1315 1315              "usbecm_send_data: bulk_len = %d", br->bulk_len);
1316 1316  
1317 1317          br->bulk_timeout = USBECM_BULKOUT_TIMEOUT;
1318 1318          br->bulk_cb = usbecm_bulkout_cb;
1319 1319          br->bulk_exc_cb = usbecm_bulkout_cb;
1320 1320          br->bulk_client_private = (usb_opaque_t)ecmp;
1321 1321          br->bulk_attributes = USB_ATTRS_AUTOCLEARING;
1322 1322  
1323 1323          if (br->bulk_data != NULL) {
1324 1324                  if (br->bulk_data->b_rptr[0] & 0x01) {
1325 1325                          mutex_enter(&ecmp->ecm_mutex);
1326 1326                          if (bcmp(br->bulk_data->b_rptr, usbecm_broadcast,
1327 1327                              ETHERADDRL) != 0) {
1328 1328                                  ecmp->ecm_stat.es_multixmt++;
1329 1329                          } else {
1330 1330                                  ecmp->ecm_stat.es_brdcstxmt++;
1331 1331                          }
1332 1332                          mutex_exit(&ecmp->ecm_mutex);
1333 1333                  }
1334 1334                  rval = usb_pipe_bulk_xfer(ecmp->ecm_bulkout_ph, br, 0);
1335 1335          }
1336 1336  
1337 1337          if (rval != USB_SUCCESS) {
1338 1338                  USB_DPRINTF_L2(PRINT_MASK_OPS, ecmp->ecm_lh,
1339 1339                      "usbecm_send_data: Send Data failed.");
1340 1340  
1341 1341                  /*
1342 1342                   * br->bulk_data should be freed because we allocated
1343 1343                   * it in this function.
1344 1344                   */
1345 1345                  usb_free_bulk_req(br);
1346 1346  
1347 1347          } else {
1348 1348                  mutex_enter(&ecmp->ecm_mutex);
1349 1349                  ecmp->ecm_tx_cnt++;
1350 1350                  mutex_exit(&ecmp->ecm_mutex);
1351 1351  
1352 1352                  /*
1353 1353                   * ECM V1.2, section 3.3.1, a short(including zero length)
1354 1354                   * packet signifies end of frame. We should send a zero length
1355 1355                   * packet to device if the total data lenght is multiple of
1356 1356                   * bulkout endpoint's max packet size.
1357 1357                   */
1358 1358                  max_pkt_size = ecmp->ecm_bulk_out_ep->ep_descr.wMaxPacketSize;
1359 1359                  if ((data_len % max_pkt_size) == 0) {
1360 1360                          if ((rval = usbecm_send_zero_data(ecmp))
1361 1361                              != USB_SUCCESS) {
1362 1362                                  USB_DPRINTF_L2(PRINT_MASK_OPS, ecmp->ecm_lh,
1363 1363                                      "usbecm_send_data: fail to send padding");
1364 1364                          }
1365 1365                  }
1366 1366          }
1367 1367  
1368 1368          if (new_data) {
1369 1369                  freemsg(new_data);
1370 1370          }
1371 1371  
1372 1372          USB_DPRINTF_L4(PRINT_MASK_EVENTS, ecmp->ecm_lh,
1373 1373              "usbecm_send_data: len(%d) data sent, rval=%d",
1374 1374              new_data_len ? new_data_len : data_len, rval);
1375 1375  
1376 1376          return (rval);
1377 1377  }
1378 1378  
1379 1379  static int
1380 1380  usbecm_send_zero_data(usbecm_state_t *ecmp)
1381 1381  {
1382 1382          usb_bulk_req_t  *br;
1383 1383          int             rval = USB_FAILURE;
1384 1384  
1385 1385          USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
1386 1386              "usbecm_send_zero_data: entry");
1387 1387  
1388 1388          br = usb_alloc_bulk_req(ecmp->ecm_dip, 0, USB_FLAGS_SLEEP);
1389 1389          if (br == NULL) {
1390 1390                  USB_DPRINTF_L2(PRINT_MASK_OPS, ecmp->ecm_lh,
1391 1391                      "usbecm_send_data: alloc req failed.");
1392 1392  
1393 1393                  return (USB_FAILURE);
1394 1394          }
1395 1395  
1396 1396          /* initialize the bulk out request */
1397 1397          br->bulk_len = 0;
1398 1398          br->bulk_timeout = USBECM_BULKOUT_TIMEOUT;
1399 1399          br->bulk_cb = usbecm_bulkout_cb;
1400 1400          br->bulk_exc_cb = usbecm_bulkout_cb;
1401 1401          br->bulk_client_private = (usb_opaque_t)ecmp;
1402 1402          br->bulk_attributes = USB_ATTRS_AUTOCLEARING;
1403 1403  
1404 1404          rval = usb_pipe_bulk_xfer(ecmp->ecm_bulkout_ph, br, 0);
1405 1405  
1406 1406          if (rval != USB_SUCCESS) {
1407 1407                  USB_DPRINTF_L2(PRINT_MASK_OPS, ecmp->ecm_lh,
1408 1408                      "usbecm_send_zero_data: Send data failed, rval=%d",
1409 1409                      rval);
1410 1410  
1411 1411                  /*
1412 1412                   * br->bulk_data should be freed because we allocated
1413 1413                   * it in this function.
1414 1414                   */
1415 1415                  usb_free_bulk_req(br);
1416 1416  
1417 1417          }
1418 1418  
1419 1419          USB_DPRINTF_L4(PRINT_MASK_OPS, ecmp->ecm_lh,
1420 1420              "usbecm_send_zero_data: end");
1421 1421  
1422 1422          return (rval);
1423 1423  }
1424 1424  
1425 1425  /*
1426 1426   * Loadable module configuration entry points
1427 1427   */
1428 1428  
1429 1429  /*
1430 1430   * _init module entry point.
1431 1431   *
1432 1432   * Called when the module is being loaded into memory.
1433 1433   */
1434 1434  int
1435 1435  _init(void)
1436 1436  {
1437 1437          int err;
1438 1438  
1439 1439          err = ddi_soft_state_init(&usbecm_statep, sizeof (usbecm_state_t), 1);
1440 1440  
1441 1441          if (err != DDI_SUCCESS)
1442 1442                  return (err);
1443 1443  
1444 1444          mac_init_ops(&usbecm_devops, "usbecm");
1445 1445          err = mod_install(&usbecm_ml);
1446 1446  
1447 1447          if (err != DDI_SUCCESS) {
1448 1448                  mac_fini_ops(&usbecm_devops);
1449 1449                  ddi_soft_state_fini(&usbecm_statep);
1450 1450          }
1451 1451  
1452 1452          return (err);
1453 1453  }
1454 1454  
1455 1455  /*
1456 1456   * _info module entry point.
1457 1457   *
1458 1458   * Called to obtain information about the module.
1459 1459   */
1460 1460  int
1461 1461  _info(struct modinfo *modinfop)
1462 1462  {
1463 1463          return (mod_info(&usbecm_ml, modinfop));
1464 1464  }
1465 1465  
1466 1466  /*
1467 1467   * _fini module entry point.
1468 1468   *
1469 1469   * Called when the module is being unloaded.
1470 1470   */
1471 1471  int
1472 1472  _fini(void)
1473 1473  {
1474 1474          int err;
1475 1475  
1476 1476          err = mod_remove(&usbecm_ml);
1477 1477          if (err == DDI_SUCCESS) {
1478 1478                  mac_fini_ops(&usbecm_devops);
1479 1479                  ddi_soft_state_fini(&usbecm_statep);
1480 1480          }
1481 1481  
1482 1482          return (err);
1483 1483  }
1484 1484  
1485 1485  /*
1486 1486   * usbecm_pipe_start_polling:
1487 1487   *      start polling on the interrupt pipe
1488 1488   */
1489 1489  static void
1490 1490  usbecm_pipe_start_polling(usbecm_state_t *ecmp)
1491 1491  {
1492 1492          usb_intr_req_t  *intr;
1493 1493          int             rval;
1494 1494  
1495 1495          USB_DPRINTF_L4(PRINT_MASK_OPEN, ecmp->ecm_lh,
1496 1496              "usbecm_pipe_start_polling: ");
1497 1497  
1498 1498          if (ecmp->ecm_intr_ph == NULL) {
1499 1499  
1500 1500                  return;
1501 1501          }
1502 1502  
1503 1503          intr = usb_alloc_intr_req(ecmp->ecm_dip, 0, USB_FLAGS_SLEEP);
1504 1504  
1505 1505          /*
1506 1506           * If it is in interrupt context, usb_alloc_intr_req will return NULL if
1507 1507           * called with SLEEP flag.
1508 1508           */
1509 1509          if (!intr) {
1510 1510                  USB_DPRINTF_L2(PRINT_MASK_OPEN, ecmp->ecm_lh,
1511 1511                      "usbecm_pipe_start_polling: alloc req failed.");
1512 1512  
1513 1513                  return;
1514 1514          }
1515 1515  
1516 1516          /* initialize the interrupt request. */
1517 1517          intr->intr_attributes = USB_ATTRS_SHORT_XFER_OK |
1518 1518              USB_ATTRS_AUTOCLEARING;
1519 1519          intr->intr_len = ecmp->ecm_intr_ep->ep_descr.wMaxPacketSize;
1520 1520          intr->intr_client_private = (usb_opaque_t)ecmp;
1521 1521          intr->intr_cb = usbecm_intr_cb;
1522 1522          intr->intr_exc_cb = usbecm_intr_ex_cb;
1523 1523  
1524 1524          rval = usb_pipe_intr_xfer(ecmp->ecm_intr_ph, intr, USB_FLAGS_SLEEP);
1525 1525  
1526 1526          mutex_enter(&ecmp->ecm_mutex);
1527 1527          if (rval == USB_SUCCESS) {
1528 1528                  ecmp->ecm_intr_state = USBECM_PIPE_BUSY;
1529 1529          } else {
1530 1530                  usb_free_intr_req(intr);
1531 1531                  ecmp->ecm_intr_state = USBECM_PIPE_IDLE;
1532 1532                  USB_DPRINTF_L3(PRINT_MASK_OPEN, ecmp->ecm_lh,
1533 1533                      "usbecm_pipe_start_polling: failed (%d)", rval);
1534 1534          }
1535 1535          mutex_exit(&ecmp->ecm_mutex);
1536 1536  
1537 1537          USB_DPRINTF_L3(PRINT_MASK_OPEN, ecmp->ecm_lh,
1538 1538              "usbecm_pipe_start_polling: end, rval=%d", rval);
1539 1539  }
1540 1540  
1541 1541  
1542 1542  /*
1543 1543   * usbsecm_intr_cb:
1544 1544   *      interrupt pipe normal callback
1545 1545   */
1546 1546  /*ARGSUSED*/
1547 1547  static void
1548 1548  usbecm_intr_cb(usb_pipe_handle_t ph, usb_intr_req_t *req)
1549 1549  {
1550 1550          usbecm_state_t *ecmp = (usbecm_state_t *)req->intr_client_private;
1551 1551          mblk_t          *data = req->intr_data;
1552 1552          int             data_len;
1553 1553  
1554 1554          data_len = (data) ? MBLKL(data) : 0;
1555 1555  
1556 1556          DTRACE_PROBE2(usbecm_intr__cb, (usb_intr_req_t *), req, int, data_len);
1557 1557  
1558 1558          /* check data length */
1559 1559          if (data_len < 8) {
1560 1560                  USB_DPRINTF_L2(PRINT_MASK_CB, ecmp->ecm_lh,
1561 1561                      "usbsecm_intr_cb: %d packet too short", data_len);
1562 1562                  usb_free_intr_req(req);
1563 1563  
1564 1564                  return;
1565 1565          }
1566 1566          req->intr_data = NULL;
1567 1567          usb_free_intr_req(req);
1568 1568  
1569 1569          mutex_enter(&ecmp->ecm_mutex);
1570 1570          /* parse interrupt data -- notifications */
1571 1571          usbecm_parse_intr_data(ecmp, data);
1572 1572          mutex_exit(&ecmp->ecm_mutex);
1573 1573  }
1574 1574  
1575 1575  
1576 1576  /*
1577 1577   * usbsecm_intr_ex_cb:
1578 1578   *      interrupt pipe exception callback
1579 1579   */
1580 1580  /*ARGSUSED*/
1581 1581  static void
1582 1582  usbecm_intr_ex_cb(usb_pipe_handle_t ph, usb_intr_req_t *req)
1583 1583  {
1584 1584          usbecm_state_t *ecmp = (usbecm_state_t *)req->intr_client_private;
1585 1585          usb_cr_t        cr = req->intr_completion_reason;
1586 1586  
1587 1587          DTRACE_PROBE2(usbecm_intr_ex__cb, int, ecmp->ecm_dev_state,
1588 1588              (usb_cr_t), cr);
1589 1589  
1590 1590          usb_free_intr_req(req);
1591 1591  
1592 1592          /*
1593 1593           * If completion reason isn't USB_CR_PIPE_CLOSING and
1594 1594           * USB_CR_STOPPED_POLLING, restart polling.
1595 1595           */
1596 1596          if ((cr != USB_CR_PIPE_CLOSING) && (cr != USB_CR_STOPPED_POLLING)) {
1597 1597                  mutex_enter(&ecmp->ecm_mutex);
1598 1598  
1599 1599                  if (ecmp->ecm_dev_state != USB_DEV_ONLINE) {
1600 1600  
1601 1601                          USB_DPRINTF_L2(PRINT_MASK_CB, ecmp->ecm_lh,
1602 1602                              "usbsecm_intr_ex_cb: state = %d",
1603 1603                              ecmp->ecm_dev_state);
1604 1604  
1605 1605                          mutex_exit(&ecmp->ecm_mutex);
1606 1606  
1607 1607                          return;
1608 1608                  }
1609 1609                  mutex_exit(&ecmp->ecm_mutex);
1610 1610  
1611 1611                  usbecm_pipe_start_polling(ecmp);
1612 1612          }
1613 1613  }
1614 1614  
1615 1615  
1616 1616  /*
1617 1617   * usbsecm_parse_intr_data:
1618 1618   *      Parse data received from interrupt callback
1619 1619   */
1620 1620  static void
1621 1621  usbecm_parse_intr_data(usbecm_state_t *ecmp, mblk_t *data)
1622 1622  {
1623 1623          uint8_t         bmRequestType;
1624 1624          uint8_t         bNotification;
1625 1625          uint16_t        wValue;
1626 1626          uint16_t        wLength;
1627 1627          int             linkstate;
1628 1628  
1629 1629          bmRequestType = data->b_rptr[0];
1630 1630          bNotification = data->b_rptr[1];
1631 1631          /*
1632 1632           * If Notification type is NETWORK_CONNECTION, wValue is 0 or 1,
1633 1633           * mLength is 0. If Notification type is SERIAL_TYPE, mValue is 0,
1634 1634           * mLength is 2. So we directly get the value from the byte.
1635 1635           */
1636 1636          wValue = data->b_rptr[2];
1637 1637          wLength = data->b_rptr[6];
1638 1638  
1639 1639          if (ecmp->ecm_compatibility) {
1640 1640                  if (bmRequestType != USB_CDC_NOTIFICATION_REQUEST_TYPE) {
1641 1641                          USB_DPRINTF_L2(PRINT_MASK_CB, ecmp->ecm_lh,
1642 1642                              "usbsecm_parse_intr_data: unknown request "
1643 1643                              "type - 0x%x", bmRequestType);
1644 1644  
1645 1645                          freemsg(data);
1646 1646  
1647 1647                          return;
1648 1648                  }
1649 1649          } else {
1650 1650                  /* non-compatible device specific parsing */
1651 1651                  if (ECM_DS_OP_VALID(ecm_ds_intr_cb)) {
1652 1652                          if (ecmp->ecm_ds_ops->ecm_ds_intr_cb(ecmp, data)
1653 1653                              != USB_SUCCESS) {
1654 1654                                  USB_DPRINTF_L2(PRINT_MASK_CB, ecmp->ecm_lh,
1655 1655                                      "usbsecm_parse_intr_data: unknown request"
1656 1656                                      "type - 0x%x", bmRequestType);
1657 1657                          }
1658 1658                  }
1659 1659                  freemsg(data);
1660 1660  
1661 1661                  return;
1662 1662          }
1663 1663  
1664 1664          /*
1665 1665           * Check the return value of compatible devices
1666 1666           */
1667 1667          switch (bNotification) {
1668 1668          case USB_CDC_NOTIFICATION_NETWORK_CONNECTION:
1669 1669                  USB_DPRINTF_L3(PRINT_MASK_CB, ecmp->ecm_lh,
1670 1670                      "usbsecm_parse_intr_data: %s network!",
1671 1671                      wValue ? "connected to" :"disconnected from");
1672 1672  
1673 1673                  linkstate = wValue ? LINK_STATE_UP:LINK_STATE_DOWN;
1674 1674                  if (ecmp->ecm_stat.es_linkstate == linkstate) {
1675 1675                  /* no changes to previous state */
1676 1676                          break;
1677 1677                  }
1678 1678  
1679 1679                  ecmp->ecm_stat.es_linkstate = linkstate;
1680 1680                  mutex_exit(&ecmp->ecm_mutex);
1681 1681                  mac_link_update(ecmp->ecm_mh, linkstate);
1682 1682                  mutex_enter(&ecmp->ecm_mutex);
1683 1683  
1684 1684                  break;
1685 1685          case USB_CDC_NOTIFICATION_RESPONSE_AVAILABLE:
1686 1686                  USB_DPRINTF_L3(PRINT_MASK_CB, ecmp->ecm_lh,
1687 1687                      "usbsecm_parse_intr_data: A response is a available.");
1688 1688  
1689 1689                  break;
1690 1690          case USB_CDC_NOTIFICATION_SPEED_CHANGE:
1691 1691                  USB_DPRINTF_L3(PRINT_MASK_CB, ecmp->ecm_lh,
1692 1692                      "usbsecm_parse_intr_data: speed change");
1693 1693  
1694 1694                  /* check the parameter's length. */
1695 1695                  if (wLength != 8) {
1696 1696                          USB_DPRINTF_L3(PRINT_MASK_CB, ecmp->ecm_lh,
1697 1697                              "usbsecm_parse_intr_data: error data length.");
1698 1698                  } else {
1699 1699                          uint32_t        us_rate, ds_rate;
1700 1700                          uint8_t         *sp;
1701 1701  
1702 1702                          sp = &data->b_rptr[8];
1703 1703                          LE_TO_UINT32(sp, us_rate);
1704 1704                          sp = &data->b_rptr[12];
1705 1705                          LE_TO_UINT32(sp, ds_rate);
1706 1706                          ecmp->ecm_stat.es_upspeed = us_rate;
1707 1707                          ecmp->ecm_stat.es_downspeed = ds_rate;
1708 1708                  }
1709 1709  
1710 1710                  break;
1711 1711          default:
1712 1712                  USB_DPRINTF_L3(PRINT_MASK_CB, ecmp->ecm_lh,
1713 1713                      "usbsecm_parse_intr_data: unknown notification - 0x%x!",
1714 1714                      bNotification);
1715 1715  
1716 1716                  break;
1717 1717          }
1718 1718  
1719 1719          freemsg(data);
1720 1720  }
1721 1721  
1722 1722  /*
1723 1723   * usbecm_restore_device_state:
1724 1724   *      restore device state after CPR resume or reconnect
1725 1725   */
1726 1726  static int
1727 1727  usbecm_restore_device_state(usbecm_state_t *ecmp)
1728 1728  {
1729 1729          int     state;
1730 1730  
1731 1731          USB_DPRINTF_L4(PRINT_MASK_EVENTS, ecmp->ecm_lh,
1732 1732              "usbecm_restore_device_state: ");
1733 1733  
1734 1734          mutex_enter(&ecmp->ecm_mutex);
1735 1735          state = ecmp->ecm_dev_state;
1736 1736          mutex_exit(&ecmp->ecm_mutex);
1737 1737  
1738 1738          /* Check device status */
1739 1739          if ((state != USB_DEV_DISCONNECTED) && (state != USB_DEV_SUSPENDED)) {
1740 1740  
1741 1741                  return (state);
1742 1742          }
1743 1743  
1744 1744          /* Check if we are talking to the same device */
1745 1745          if (usb_check_same_device(ecmp->ecm_dip, ecmp->ecm_lh, USB_LOG_L0,
1746 1746              -1, USB_CHK_ALL, NULL) != USB_SUCCESS) {
1747 1747                  mutex_enter(&ecmp->ecm_mutex);
1748 1748                  state = ecmp->ecm_dev_state = USB_DEV_DISCONNECTED;
1749 1749                  mutex_exit(&ecmp->ecm_mutex);
1750 1750  
1751 1751                  return (state);
1752 1752          }
1753 1753  
1754 1754          if (state == USB_DEV_DISCONNECTED) {
1755 1755                  USB_DPRINTF_L1(PRINT_MASK_EVENTS, ecmp->ecm_lh,
1756 1756                      "usbecm_restore_device_state: Device has been reconnected "
1757 1757                      "but data may have been lost");
1758 1758          }
1759 1759  
1760 1760          /* if MAC was started, restarted it */
1761 1761          mutex_enter(&ecmp->ecm_mutex);
1762 1762          if (ecmp->ecm_mac_state == USBECM_MAC_STARTED) {
1763 1763                  USB_DPRINTF_L3(PRINT_MASK_EVENTS, ecmp->ecm_lh,
1764 1764                      "usbecm_restore_device_state: MAC was started");
1765 1765  
1766 1766                  mutex_exit(&ecmp->ecm_mutex);
1767 1767                  /* Do the same operation as usbecm_m_start() does */
1768 1768                  if (usbecm_open_pipes(ecmp) != USB_SUCCESS) {
1769 1769  
1770 1770                          return (state);
1771 1771                  }
1772 1772  
1773 1773                  mutex_enter(&ecmp->ecm_mutex);
1774 1774                  if (usbecm_rx_start(ecmp) != USB_SUCCESS) {
1775 1775                          mutex_exit(&ecmp->ecm_mutex);
1776 1776  
1777 1777                          return (state);
1778 1778                  }
1779 1779          }
1780 1780          mutex_exit(&ecmp->ecm_mutex);
1781 1781  
1782 1782          /*
1783 1783           * init device state
1784 1784           */
1785 1785          mutex_enter(&ecmp->ecm_mutex);
1786 1786          state = ecmp->ecm_dev_state = USB_DEV_ONLINE;
1787 1787          mutex_exit(&ecmp->ecm_mutex);
1788 1788  
1789 1789          return (state);
1790 1790  }
1791 1791  
1792 1792  /*
1793 1793   * usbecm_reconnect_event_cb:
1794 1794   *     called upon when the device is hotplugged back
1795 1795   */
1796 1796  /*ARGSUSED*/
1797 1797  static int
1798 1798  usbecm_reconnect_event_cb(dev_info_t *dip)
1799 1799  {
1800 1800          usbecm_state_t  *ecmp =
1801 1801              (usbecm_state_t *)ddi_get_soft_state(usbecm_statep,
1802 1802              ddi_get_instance(dip));
1803 1803  
1804 1804          ASSERT(ecmp != NULL);
1805 1805  
1806 1806          USB_DPRINTF_L4(PRINT_MASK_EVENTS, ecmp->ecm_lh,
1807 1807              "usbecm_reconnect_event_cb: entry");
1808 1808  
1809 1809          (void) usb_serialize_access(ecmp->ecm_ser_acc, USB_WAIT, 0);
1810 1810  
1811 1811          mutex_enter(&ecmp->ecm_mutex);
1812 1812          ASSERT(ecmp->ecm_dev_state == USB_DEV_DISCONNECTED);
1813 1813  
1814 1814          mutex_exit(&ecmp->ecm_mutex);
1815 1815  
1816 1816          if (usbecm_restore_device_state(ecmp) != USB_DEV_ONLINE) {
1817 1817                  usb_release_access(ecmp->ecm_ser_acc);
1818 1818  
1819 1819                  return (USB_FAILURE);
1820 1820          }
1821 1821  
1822 1822          usb_release_access(ecmp->ecm_ser_acc);
1823 1823  
1824 1824          return (USB_SUCCESS);
1825 1825  }
1826 1826  
1827 1827  
1828 1828  /*
1829 1829   * usbecm_disconnect_event_cb:
1830 1830   *      callback for disconnect events
1831 1831   */
1832 1832  /*ARGSUSED*/
1833 1833  static int
1834 1834  usbecm_disconnect_event_cb(dev_info_t *dip)
1835 1835  {
1836 1836          usbecm_state_t  *ecmp = (usbecm_state_t *)ddi_get_soft_state(
1837 1837              usbecm_statep, ddi_get_instance(dip));
1838 1838  
1839 1839          USB_DPRINTF_L4(PRINT_MASK_EVENTS, ecmp->ecm_lh,
1840 1840              "usbecm_disconnect_event_cb: entry");
1841 1841  
1842 1842          (void) usb_serialize_access(ecmp->ecm_ser_acc, USB_WAIT, 0);
1843 1843  
1844 1844          mutex_enter(&ecmp->ecm_mutex);
1845 1845          ecmp->ecm_dev_state = USB_DEV_DISCONNECTED;
1846 1846          mutex_exit(&ecmp->ecm_mutex);
1847 1847  
1848 1848          usbecm_close_pipes(ecmp);
1849 1849  
1850 1850          usb_release_access(ecmp->ecm_ser_acc);
1851 1851  
1852 1852          USB_DPRINTF_L4(PRINT_MASK_EVENTS, ecmp->ecm_lh,
1853 1853              "usbecm_disconnect_event_cb: End");
1854 1854  
1855 1855          return (USB_SUCCESS);
1856 1856  }
1857 1857  
1858 1858  /*
1859 1859   * power management
1860 1860   * ----------------
1861 1861   *
1862 1862   * usbecm_create_pm_components:
1863 1863   *      create PM components
1864 1864   */
1865 1865  static int
1866 1866  usbecm_create_pm_components(usbecm_state_t *ecmp)
1867 1867  {
1868 1868          dev_info_t      *dip = ecmp->ecm_dip;
1869 1869          usbecm_pm_t     *pm;
1870 1870          uint_t          pwr_states;
1871 1871  
1872 1872          USB_DPRINTF_L4(PRINT_MASK_PM, ecmp->ecm_lh,
1873 1873              "usbecm_create_pm_components: entry");
1874 1874  
1875 1875          if (usb_create_pm_components(dip, &pwr_states) != USB_SUCCESS) {
1876 1876                  USB_DPRINTF_L2(PRINT_MASK_PM, ecmp->ecm_lh,
1877 1877                      "usbecm_create_pm_components: failed");
1878 1878  
1879 1879                  /* don't fail the attach process */
1880 1880                  return (USB_SUCCESS);
1881 1881          }
1882 1882  
1883 1883          pm = ecmp->ecm_pm =
1884 1884              (usbecm_pm_t *)kmem_zalloc(sizeof (usbecm_pm_t), KM_SLEEP);
1885 1885  
1886 1886          pm->pm_pwr_states = (uint8_t)pwr_states;
1887 1887          pm->pm_cur_power = USB_DEV_OS_FULL_PWR;
1888 1888          pm->pm_wakeup_enabled = (usb_handle_remote_wakeup(dip,
1889 1889              USB_REMOTE_WAKEUP_ENABLE) == USB_SUCCESS);
1890 1890  
1891 1891          (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
1892 1892  
1893 1893          return (USB_SUCCESS);
1894 1894  }
1895 1895  
1896 1896  /*
1897 1897   * usbecm_cleanup:
1898 1898   *      Release resources of current device during detach.
1899 1899   */
1900 1900  static void
1901 1901  usbecm_cleanup(usbecm_state_t *ecmp)
1902 1902  {
1903 1903          USB_DPRINTF_L4(PRINT_MASK_CLOSE, ecmp->ecm_lh,
1904 1904              "usbecm_cleanup: ");
1905 1905  
1906 1906          if (ecmp == NULL) {
1907 1907  
1908 1908                  return;
1909 1909          }
1910 1910  
1911 1911          usbecm_close_pipes(ecmp);
1912 1912  
1913 1913          /* unregister callback function */
1914 1914          if (ecmp->ecm_init_flags & USBECM_INIT_EVENTS) {
1915 1915                  USB_DPRINTF_L4(PRINT_MASK_CLOSE, ecmp->ecm_lh,
1916 1916                      "usbecm_cleanup: unregister events");
1917 1917  
1918 1918                  usb_unregister_event_cbs(ecmp->ecm_dip, &usbecm_events);
1919 1919          }
1920 1920  
1921 1921          /* destroy power management components */
1922 1922          if (ecmp->ecm_pm != NULL) {
1923 1923                  USB_DPRINTF_L4(PRINT_MASK_CLOSE, ecmp->ecm_lh,
1924 1924                      "usbecm_cleanup: destroy pm");
1925 1925                  usbecm_destroy_pm_components(ecmp);
1926 1926          }
1927 1927  
1928 1928          /* free description of device tree. */
1929 1929          if (ecmp->ecm_def_ph != NULL) {
1930 1930                  mutex_destroy(&ecmp->ecm_mutex);
1931 1931  
1932 1932                  usb_free_descr_tree(ecmp->ecm_dip, ecmp->ecm_dev_data);
1933 1933                  ecmp->ecm_def_ph = NULL;
1934 1934          }
1935 1935  
1936 1936          if (ecmp->ecm_lh != NULL) {
1937 1937                  usb_free_log_hdl(ecmp->ecm_lh);
1938 1938                  ecmp->ecm_lh = NULL;
1939 1939          }
1940 1940  
1941 1941          /* detach client device */
1942 1942          if (ecmp->ecm_dev_data != NULL) {
1943 1943                  usb_client_detach(ecmp->ecm_dip, ecmp->ecm_dev_data);
1944 1944          }
1945 1945  
1946 1946          if (ecmp->ecm_init_flags & USBECM_INIT_MAC) {
1947 1947                  (void) usbecm_mac_fini(ecmp);
1948 1948          }
1949 1949  
1950 1950          if (ecmp->ecm_init_flags & USBECM_INIT_SER) {
1951 1951                  usb_fini_serialization(ecmp->ecm_ser_acc);
1952 1952          }
1953 1953  
1954 1954          ddi_prop_remove_all(ecmp->ecm_dip);
1955 1955          ddi_remove_minor_node(ecmp->ecm_dip, NULL);
1956 1956  }
1957 1957  
1958 1958  /*
1959 1959   * usbecm_destroy_pm_components:
1960 1960   *      destroy PM components
1961 1961   */
1962 1962  static void
1963 1963  usbecm_destroy_pm_components(usbecm_state_t *ecmp)
1964 1964  {
1965 1965          usbecm_pm_t     *pm = ecmp->ecm_pm;
1966 1966          dev_info_t      *dip = ecmp->ecm_dip;
1967 1967          int             rval;
1968 1968  
1969 1969          USB_DPRINTF_L4(PRINT_MASK_PM, ecmp->ecm_lh,
1970 1970              "usbecm_destroy_pm_components: ");
1971 1971  
1972 1972          if (ecmp->ecm_dev_state != USB_DEV_DISCONNECTED) {
1973 1973                  if (pm->pm_wakeup_enabled) {
1974 1974                          rval = pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
1975 1975                          if (rval != DDI_SUCCESS) {
1976 1976                                  USB_DPRINTF_L2(PRINT_MASK_PM, ecmp->ecm_lh,
1977 1977                                      "usbecm_destroy_pm_components: "
1978 1978                                      "raising power failed (%d)", rval);
1979 1979                          }
1980 1980  
1981 1981                          rval = usb_handle_remote_wakeup(dip,
1982 1982                              USB_REMOTE_WAKEUP_DISABLE);
1983 1983                          if (rval != USB_SUCCESS) {
1984 1984                                  USB_DPRINTF_L2(PRINT_MASK_PM, ecmp->ecm_lh,
1985 1985                                      "usbecm_destroy_pm_components: "
1986 1986                                      "disable remote wakeup failed (%d)", rval);
1987 1987                          }
1988 1988                  }
1989 1989  
1990 1990                  (void) pm_lower_power(dip, 0, USB_DEV_OS_PWR_OFF);
1991 1991          }
1992 1992          kmem_free((caddr_t)pm, sizeof (usbecm_pm_t));
1993 1993          ecmp->ecm_pm = NULL;
1994 1994  }
1995 1995  
1996 1996  /*
1997 1997   * usbecm_pm_set_busy:
1998 1998   *      mark device busy and raise power
1999 1999   */
2000 2000  static void
2001 2001  usbecm_pm_set_busy(usbecm_state_t *ecmp)
2002 2002  {
2003 2003          usbecm_pm_t     *pm = ecmp->ecm_pm;
2004 2004          dev_info_t      *dip = ecmp->ecm_dip;
2005 2005          int             rval;
2006 2006  
2007 2007          USB_DPRINTF_L4(PRINT_MASK_PM, ecmp->ecm_lh,
2008 2008              "usbecm_pm_set_busy: pm = 0x%p", (void *)pm);
2009 2009  
2010 2010          if (pm == NULL) {
2011 2011  
2012 2012                  return;
2013 2013          }
2014 2014  
2015 2015          mutex_enter(&ecmp->ecm_mutex);
2016 2016          /* if already marked busy, just increment the counter */
2017 2017          if (pm->pm_busy_cnt++ > 0) {
2018 2018                  mutex_exit(&ecmp->ecm_mutex);
2019 2019  
2020 2020                  return;
2021 2021          }
2022 2022  
2023 2023          (void) pm_busy_component(dip, 0);
2024 2024  
2025 2025          if (pm->pm_cur_power == USB_DEV_OS_FULL_PWR) {
2026 2026                  mutex_exit(&ecmp->ecm_mutex);
2027 2027  
2028 2028                  return;
2029 2029          }
2030 2030  
2031 2031          /* need to raise power  */
2032 2032          pm->pm_raise_power = B_TRUE;
2033 2033          mutex_exit(&ecmp->ecm_mutex);
2034 2034  
2035 2035          rval = pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
2036 2036          if (rval != DDI_SUCCESS) {
2037 2037                  USB_DPRINTF_L2(PRINT_MASK_PM, ecmp->ecm_lh,
2038 2038                      "usbecm_pm_set_busy: raising power failed");
2039 2039          }
2040 2040  
2041 2041          mutex_enter(&ecmp->ecm_mutex);
2042 2042          pm->pm_raise_power = B_FALSE;
2043 2043          mutex_exit(&ecmp->ecm_mutex);
2044 2044  }
2045 2045  
2046 2046  
2047 2047  /*
2048 2048   * usbecm_pm_set_idle:
2049 2049   *      mark device idle
2050 2050   */
2051 2051  static void
2052 2052  usbecm_pm_set_idle(usbecm_state_t *ecmp)
2053 2053  {
2054 2054          usbecm_pm_t     *pm = ecmp->ecm_pm;
2055 2055          dev_info_t      *dip = ecmp->ecm_dip;
2056 2056  
2057 2057          USB_DPRINTF_L4(PRINT_MASK_PM, ecmp->ecm_lh,
2058 2058              "usbecm_pm_set_idle: ");
2059 2059  
2060 2060          if (pm == NULL) {
2061 2061  
2062 2062                  return;
2063 2063          }
2064 2064  
2065 2065          mutex_enter(&ecmp->ecm_mutex);
2066 2066          if (--pm->pm_busy_cnt > 0) {
2067 2067                  mutex_exit(&ecmp->ecm_mutex);
2068 2068  
2069 2069                  return;
2070 2070          }
2071 2071  
2072 2072          if (pm) {
2073 2073                  (void) pm_idle_component(dip, 0);
2074 2074          }
2075 2075          mutex_exit(&ecmp->ecm_mutex);
2076 2076  }
2077 2077  
2078 2078  
2079 2079  /*
2080 2080   * usbecm_pwrlvl0:
2081 2081   *      Functions to handle power transition for OS levels 0 -> 3
2082 2082   *      The same level as OS state, different from USB state
2083 2083   */
2084 2084  static int
2085 2085  usbecm_pwrlvl0(usbecm_state_t *ecmp)
2086 2086  {
2087 2087          int             rval;
2088 2088  
2089 2089          ASSERT(mutex_owned(&ecmp->ecm_mutex));
2090 2090  
2091 2091          USB_DPRINTF_L4(PRINT_MASK_PM, ecmp->ecm_lh,
2092 2092              "usbecm_pwrlvl0: ");
2093 2093  
2094 2094          switch (ecmp->ecm_dev_state) {
2095 2095          case USB_DEV_ONLINE:
2096 2096                  /* issue USB D3 command to the device */
2097 2097                  rval = usb_set_device_pwrlvl3(ecmp->ecm_dip);
2098 2098                  ASSERT(rval == USB_SUCCESS);
2099 2099                  if ((ecmp->ecm_intr_ph != NULL) &&
2100 2100                      (ecmp->ecm_intr_state == USBECM_PIPE_BUSY)) {
2101 2101                          mutex_exit(&ecmp->ecm_mutex);
2102 2102                          usb_pipe_stop_intr_polling(ecmp->ecm_intr_ph,
2103 2103                              USB_FLAGS_SLEEP);
2104 2104                          mutex_enter(&ecmp->ecm_mutex);
2105 2105  
2106 2106                          ecmp->ecm_intr_state = USBECM_PIPE_IDLE;
2107 2107                  }
2108 2108                  ecmp->ecm_dev_state = USB_DEV_PWRED_DOWN;
2109 2109                  ecmp->ecm_pm->pm_cur_power = USB_DEV_OS_PWR_OFF;
2110 2110  
2111 2111                  /* FALLTHRU */
2112 2112          case USB_DEV_DISCONNECTED:
2113 2113          case USB_DEV_SUSPENDED:
2114 2114                  /* allow a disconnect/cpr'ed device to go to lower power */
2115 2115  
2116 2116                  return (USB_SUCCESS);
2117 2117          case USB_DEV_PWRED_DOWN:
2118 2118          default:
2119 2119                  USB_DPRINTF_L2(PRINT_MASK_PM, ecmp->ecm_lh,
2120 2120                      "usbecm_pwrlvl0: illegal device state");
2121 2121  
2122 2122                  return (USB_FAILURE);
2123 2123          }
2124 2124  }
2125 2125  
2126 2126  
2127 2127  /*
2128 2128   * usbecm_pwrlvl1:
2129 2129   *      Functions to handle power transition for OS levels 1 -> 2
2130 2130   */
2131 2131  static int
2132 2132  usbecm_pwrlvl1(usbecm_state_t *ecmp)
2133 2133  {
2134 2134          /* issue USB D2 command to the device */
2135 2135          (void) usb_set_device_pwrlvl2(ecmp->ecm_dip);
2136 2136  
2137 2137          return (USB_FAILURE);
2138 2138  }
2139 2139  
2140 2140  
2141 2141  /*
2142 2142   * usbecm_pwrlvl2:
2143 2143   *      Functions to handle power transition for OS levels 2 -> 1
2144 2144   */
2145 2145  static int
2146 2146  usbecm_pwrlvl2(usbecm_state_t *ecmp)
2147 2147  {
2148 2148          /* issue USB D1 command to the device */
2149 2149          (void) usb_set_device_pwrlvl1(ecmp->ecm_dip);
2150 2150  
2151 2151          return (USB_FAILURE);
2152 2152  }
2153 2153  
2154 2154  
2155 2155  /*
2156 2156   * usbecm_pwrlvl3:
2157 2157   *      Functions to handle power transition for OS levels 3 -> 0
2158 2158   *      The same level as OS state, different from USB state
2159 2159   */
2160 2160  static int
2161 2161  usbecm_pwrlvl3(usbecm_state_t *ecmp)
2162 2162  {
2163 2163          int             rval;
2164 2164  
2165 2165          USB_DPRINTF_L4(PRINT_MASK_PM, ecmp->ecm_lh,
2166 2166              "usbecm_pwrlvl3: ");
2167 2167  
2168 2168          ASSERT(mutex_owned(&ecmp->ecm_mutex));
2169 2169  
2170 2170          switch (ecmp->ecm_dev_state) {
2171 2171          case USB_DEV_PWRED_DOWN:
2172 2172                  /* Issue USB D0 command to the device here */
2173 2173                  rval = usb_set_device_pwrlvl0(ecmp->ecm_dip);
2174 2174                  ASSERT(rval == USB_SUCCESS);
2175 2175  
2176 2176                  if (ecmp->ecm_intr_ph != NULL &&
2177 2177                      ecmp->ecm_intr_state == USBECM_PIPE_IDLE) {
2178 2178                          mutex_exit(&ecmp->ecm_mutex);
2179 2179                          usbecm_pipe_start_polling(ecmp);
2180 2180                          mutex_enter(&ecmp->ecm_mutex);
2181 2181                  }
2182 2182  
2183 2183                  ecmp->ecm_dev_state = USB_DEV_ONLINE;
2184 2184                  ecmp->ecm_pm->pm_cur_power = USB_DEV_OS_FULL_PWR;
2185 2185  
2186 2186                  /* FALLTHRU */
2187 2187          case USB_DEV_ONLINE:
2188 2188                  /* we are already in full power */
2189 2189  
2190 2190                  /* FALLTHRU */
2191 2191          case USB_DEV_DISCONNECTED:
2192 2192          case USB_DEV_SUSPENDED:
2193 2193  
2194 2194                  return (USB_SUCCESS);
2195 2195          default:
2196 2196                  USB_DPRINTF_L2(PRINT_MASK_PM, ecmp->ecm_lh,
2197 2197                      "usbecm_pwrlvl3: illegal device state");
2198 2198  
2199 2199                  return (USB_FAILURE);
2200 2200          }
2201 2201  }
2202 2202  
2203 2203  /*ARGSUSED*/
2204 2204  static int
2205 2205  usbecm_power(dev_info_t *dip, int comp, int level)
2206 2206  {
2207 2207          usbecm_state_t  *ecmp;
2208 2208          usbecm_pm_t     *pm;
2209 2209          int             rval = USB_SUCCESS;
2210 2210  
2211 2211          ecmp = ddi_get_soft_state(usbecm_statep, ddi_get_instance(dip));
2212 2212          pm = ecmp->ecm_pm;
2213 2213  
2214 2214          USB_DPRINTF_L4(PRINT_MASK_PM, ecmp->ecm_lh,
2215 2215              "usbecm_power: entry");
2216 2216  
2217 2217          /* check if pm is NULL */
2218 2218          if (pm == NULL) {
2219 2219                  USB_DPRINTF_L2(PRINT_MASK_PM, ecmp->ecm_lh,
2220 2220                      "usbecm_power: pm is NULL.");
2221 2221  
2222 2222                  return (USB_FAILURE);
2223 2223          }
2224 2224  
2225 2225          mutex_enter(&ecmp->ecm_mutex);
2226 2226          /*
2227 2227           * check if we are transitioning to a legal power level
2228 2228           */
2229 2229          if (USB_DEV_PWRSTATE_OK(pm->pm_pwr_states, level)) {
2230 2230                  USB_DPRINTF_L2(PRINT_MASK_PM, ecmp->ecm_lh,
2231 2231                      "usbecm_power: "
2232 2232                      "illegal power level %d, pwr_states=%x",
2233 2233                      level, pm->pm_pwr_states);
2234 2234                  mutex_exit(&ecmp->ecm_mutex);
2235 2235  
2236 2236                  return (USB_FAILURE);
2237 2237          }
2238 2238  
2239 2239          /*
2240 2240           * if we are about to raise power and asked to lower power, fail
2241 2241           */
2242 2242          if (pm->pm_raise_power && (level < (int)pm->pm_cur_power)) {
2243 2243                  USB_DPRINTF_L2(PRINT_MASK_PM, ecmp->ecm_lh,
2244 2244                      "usbecm_power: wrong condition.");
2245 2245                  mutex_exit(&ecmp->ecm_mutex);
2246 2246  
2247 2247                  return (USB_FAILURE);
2248 2248          }
2249 2249  
2250 2250          /*
2251 2251           * Set the power status of device by request level.
2252 2252           */
2253 2253          switch (level) {
2254 2254          case USB_DEV_OS_PWR_OFF:
2255 2255                  rval = usbecm_pwrlvl0(ecmp);
2256 2256  
2257 2257                  break;
2258 2258          case USB_DEV_OS_PWR_1:
2259 2259                  rval = usbecm_pwrlvl1(ecmp);
2260 2260  
2261 2261                  break;
2262 2262          case USB_DEV_OS_PWR_2:
2263 2263                  rval = usbecm_pwrlvl2(ecmp);
2264 2264  
2265 2265                  break;
2266 2266          case USB_DEV_OS_FULL_PWR:
2267 2267                  rval = usbecm_pwrlvl3(ecmp);
2268 2268  
2269 2269                  break;
2270 2270          }
2271 2271  
2272 2272          mutex_exit(&ecmp->ecm_mutex);
2273 2273  
2274 2274          return (rval);
2275 2275  }
2276 2276  
2277 2277  /*
2278 2278   * Register with the MAC layer.
2279 2279   */
2280 2280  static int
2281 2281  usbecm_mac_init(usbecm_state_t *ecmp)
2282 2282  {
2283 2283          mac_register_t *macp;
2284 2284          int err;
2285 2285  
2286 2286          /*
2287 2287           * Initialize mac structure
2288 2288           */
2289 2289          macp = mac_alloc(MAC_VERSION);
2290 2290          if (macp == NULL) {
2291 2291                  USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
2292 2292                      "failed to allocate MAC structure");
2293 2293  
2294 2294                  return (USB_FAILURE);
2295 2295          }
2296 2296  
2297 2297          /*
2298 2298           * Initialize pointer to device specific functions
2299 2299           */
2300 2300          macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
2301 2301          macp->m_driver = ecmp;
2302 2302          macp->m_dip = ecmp->ecm_dip;
2303 2303  
2304 2304          macp->m_src_addr = ecmp->ecm_srcaddr;
2305 2305          macp->m_callbacks = &usbecm_m_callbacks;
2306 2306          macp->m_min_sdu = 0;
2307 2307          macp->m_max_sdu = ETHERMTU;
2308 2308  
2309 2309          /*
2310 2310           * Register the macp to mac
2311 2311           */
2312 2312          err = mac_register(macp, &ecmp->ecm_mh);
2313 2313          mac_free(macp);
2314 2314  
2315 2315          if (err != DDI_SUCCESS) {
2316 2316                  USB_DPRINTF_L1(PRINT_MASK_ATTA, ecmp->ecm_lh,
2317 2317                      "failed to register MAC structure");
2318 2318  
2319 2319                  return (USB_FAILURE);
2320 2320          }
2321 2321  
2322 2322          mac_link_update(ecmp->ecm_mh, LINK_STATE_DOWN);
2323 2323          ecmp->ecm_stat.es_linkstate = LINK_STATE_DOWN;
2324 2324          ecmp->ecm_tx_cnt = 0;
2325 2325  
2326 2326          return (USB_SUCCESS);
2327 2327  }
2328 2328  
2329 2329  static int
2330 2330  usbecm_mac_fini(usbecm_state_t *ecmp)
2331 2331  {
2332 2332          int rval = DDI_SUCCESS;
2333 2333  
2334 2334          if ((ecmp->ecm_init_flags & USBECM_INIT_MAC) == 0) {
2335 2335                  return (DDI_SUCCESS);
2336 2336          }
2337 2337  
2338 2338          ecmp->ecm_init_flags &= ~USBECM_INIT_MAC;
2339 2339          if ((rval = mac_disable(ecmp->ecm_mh)) != 0) {
2340 2340                  USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
2341 2341                      "failed to disable MAC");
2342 2342  
2343 2343                  return (rval);
2344 2344          }
2345 2345  
2346 2346          (void) mac_unregister(ecmp->ecm_mh);
2347 2347  
2348 2348          return (rval);
2349 2349  }
2350 2350  
2351 2351  static int
2352 2352  usbecm_resume(usbecm_state_t *ecmp)
2353 2353  {
2354 2354          int             current_state;
2355 2355          int             ret;
2356 2356  
2357 2357          USB_DPRINTF_L4(PRINT_MASK_PM, ecmp->ecm_lh,
2358 2358              "usbecm_resume: ");
2359 2359  
2360 2360          mutex_enter(&ecmp->ecm_mutex);
2361 2361          current_state = ecmp->ecm_dev_state;
2362 2362          mutex_exit(&ecmp->ecm_mutex);
2363 2363  
2364 2364          /* restore the status of device */
2365 2365          if (current_state != USB_DEV_ONLINE) {
2366 2366                  ret = usbecm_restore_device_state(ecmp);
2367 2367          } else {
2368 2368                  ret = USB_DEV_ONLINE;
2369 2369          }
2370 2370  
2371 2371          return (ret);
2372 2372  }
2373 2373  
2374 2374  static int
2375 2375  usbecm_suspend(usbecm_state_t *ecmp)
2376 2376  {
2377 2377          (void) usb_serialize_access(ecmp->ecm_ser_acc, USB_WAIT, 0);
2378 2378  
2379 2379          mutex_enter(&ecmp->ecm_mutex);
2380 2380          ecmp->ecm_dev_state = USB_DEV_SUSPENDED;
2381 2381          mutex_exit(&ecmp->ecm_mutex);
2382 2382  
2383 2383          usbecm_close_pipes(ecmp);
2384 2384  
2385 2385          usb_release_access(ecmp->ecm_ser_acc);
2386 2386  
2387 2387          return (0);
2388 2388  }
2389 2389  
2390 2390  /*
2391 2391   * Translate MAC address from string to 6 bytes array int value
2392 2392   * Can't use ether_aton() since it requires format of x:x:x:x:x:x
2393 2393   */
2394 2394  void
2395 2395  label_to_mac(char *hex, unsigned char *mac)
2396 2396  {
2397 2397          int i;
2398 2398          char c;
2399 2399  
2400 2400          /* can only count 6 bytes! */
2401 2401          for (i = 0; i < 6; i++) {
2402 2402                  /* upper 4 bits */
2403 2403                  if (!isdigit(hex[2*i])) {
2404 2404                          c = (toupper(hex[2 * i]) - 'A' + 10);
2405 2405                  } else {
2406 2406                          c = (hex[2 * i] - '0');
2407 2407                  }
2408 2408                  mac[i] = c * 16;
2409 2409  
2410 2410                  /* lower 4 bits */
2411 2411                  if (!isdigit(hex[2*i + 1])) {
2412 2412                          c = (toupper(hex[2 * i + 1]) - 'A' + 10);
2413 2413                  } else {
2414 2414                          c = hex[2 * i + 1] - '0';
2415 2415                  }
2416 2416                  mac[i] += c;
2417 2417          }
2418 2418  }
2419 2419  
2420 2420  /*
2421 2421   * usbecm_get_descriptors:
2422 2422   *      parse functional descriptors of ecm compatible device
2423 2423   */
2424 2424  static int
2425 2425  usbecm_get_descriptors(usbecm_state_t *ecmp)
2426 2426  {
2427 2427          int                     i;
2428 2428          usb_cfg_data_t          *cfg;
2429 2429          usb_alt_if_data_t       *altif;
2430 2430          usb_cvs_data_t          *cvs;
2431 2431          int16_t                 master_if = -1, slave_if = -1;
2432 2432          usb_cdc_ecm_descr_t     ecm_desc;
2433 2433          usb_ep_data_t           *ep_data;
2434 2434          usb_dev_descr_t         *usb_dev_desc;
2435 2435  
2436 2436          USB_DPRINTF_L4(PRINT_MASK_ATTA, ecmp->ecm_lh,
2437 2437              "usbecm_get_descriptors: ");
2438 2438  
2439 2439          usb_dev_desc = ecmp->ecm_dev_data->dev_descr;
2440 2440  
2441 2441          /*
2442 2442           * Special treatment of Sun's SP Ethernet device.
2443 2443           */
2444 2444          if ((usb_dev_desc->idVendor == SUN_SP_VENDOR_ID) &&
2445 2445              (usb_dev_desc->idProduct == SUN_SP_PRODUCT_ID)) {
2446 2446                  if (usb_set_cfg(ecmp->ecm_dip, ecmp->ecm_cfg_index,
2447 2447                      USB_FLAGS_SLEEP, NULL, NULL) != USB_SUCCESS) {
2448 2448                          USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
2449 2449                              "usbecm_get_descriptors: fail to set cfg ");
2450 2450                  } else {
2451 2451                          usb_free_dev_data(ecmp->ecm_dip, ecmp->ecm_dev_data);
2452 2452                          if (usb_get_dev_data(ecmp->ecm_dip, &ecmp->ecm_dev_data,
2453 2453                              USB_PARSE_LVL_ALL, 0) != USB_SUCCESS) {
2454 2454                                  USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
2455 2455                                      "usbecm_get_descriptors: fail to get"
2456 2456                                      " dev_data");
2457 2457  
2458 2458                                  return (USB_FAILURE);
2459 2459                          }
2460 2460                  }
2461 2461          }
2462 2462  
2463 2463          cfg = ecmp->ecm_dev_data->dev_curr_cfg;
2464 2464  
2465 2465          /* set default control and data interface */
2466 2466          ecmp->ecm_ctrl_if_no = ecmp->ecm_data_if_no = 0;
2467 2467  
2468 2468          /* get current interfaces */
2469 2469          ecmp->ecm_ctrl_if_no = ecmp->ecm_dev_data->dev_curr_if;
2470 2470          if (cfg->cfg_if[ecmp->ecm_ctrl_if_no].if_n_alt == 0) {
2471 2471                  USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
2472 2472                      "usbecm_get_descriptors: elements in if_alt is %d",
2473 2473                      cfg->cfg_if[ecmp->ecm_ctrl_if_no].if_n_alt);
2474 2474  
2475 2475                  return (USB_FAILURE);
2476 2476          }
2477 2477  
2478 2478          altif = &cfg->cfg_if[ecmp->ecm_ctrl_if_no].if_alt[0];
2479 2479  
2480 2480          /*
2481 2481           * Based on CDC specification, ECM devices usually include the
2482 2482           * following function descriptors: Header, Union and ECM
2483 2483           * Contry Selection function descriptors. This loop search tree data
2484 2484           * structure for each ecm class descriptor.
2485 2485           */
2486 2486          for (i = 0; i < altif->altif_n_cvs; i++) {
2487 2487                  cvs = &altif->altif_cvs[i];
2488 2488  
2489 2489                  if ((cvs->cvs_buf == NULL) ||
2490 2490                      (cvs->cvs_buf[1] != USB_CDC_CS_INTERFACE)) {
2491 2491                          continue;
2492 2492                  }
2493 2493  
2494 2494                  switch (cvs->cvs_buf[2]) {
2495 2495                  case USB_CDC_DESCR_TYPE_HEADER:
2496 2496                          /*
2497 2497                           * parse header functional descriptor
2498 2498                           * Just to check integrity.
2499 2499                           */
2500 2500                          if (cvs->cvs_buf_len != 5) {
2501 2501                                  return (USB_FAILURE);
2502 2502                          }
2503 2503                          break;
2504 2504                  case USB_CDC_DESCR_TYPE_ETHERNET:
2505 2505                          /* parse ECM functional descriptor */
2506 2506                          if (cvs->cvs_buf_len >= USB_CDC_ECM_LEN) {
2507 2507                                  char buf[USB_MAXSTRINGLEN];
2508 2508  
2509 2509                                  if (usb_parse_data("4cl2sc", cvs->cvs_buf,
2510 2510                                      cvs->cvs_buf_len, (void *)&ecm_desc,
2511 2511                                      (size_t)USB_CDC_ECM_LEN) <
2512 2512                                      USB_CDC_ECM_LEN) {
2513 2513  
2514 2514                                          return (USB_FAILURE);
2515 2515                                  }
2516 2516  
2517 2517                                  /* get the MAC address */
2518 2518                                  if (usb_get_string_descr(ecmp->ecm_dip,
2519 2519                                      USB_LANG_ID, ecm_desc.iMACAddress, buf,
2520 2520                                      USB_MAXSTRINGLEN) != USB_SUCCESS) {
2521 2521  
2522 2522                                          return (USB_FAILURE);
2523 2523                                  }
2524 2524  
2525 2525                                  USB_DPRINTF_L3(PRINT_MASK_ATTA, ecmp->ecm_lh,
2526 2526                                      "usbecm_get_descriptors: macaddr=%s ",
2527 2527                                      buf);
2528 2528  
2529 2529                                  /* expects 12 characters */
2530 2530                                  if (strlen(buf) < 12) {
2531 2531                                          return (USB_FAILURE);
2532 2532                                  }
2533 2533                                  label_to_mac(buf, ecmp->ecm_srcaddr);
2534 2534  
2535 2535                                  bcopy(&ecm_desc, &ecmp->ecm_desc,
2536 2536                                      USB_CDC_ECM_LEN);
2537 2537                          }
2538 2538                          break;
2539 2539                  case USB_CDC_DESCR_TYPE_UNION:
2540 2540                          /* parse Union functional descriptor. */
2541 2541                          if (cvs->cvs_buf_len >= 5) {
2542 2542                                  master_if = cvs->cvs_buf[3];
2543 2543                                  slave_if = cvs->cvs_buf[4];
2544 2544                          }
2545 2545                          break;
2546 2546                  default:
2547 2547                          break;
2548 2548                  }
2549 2549          }
2550 2550  
2551 2551          /* For usb ecm devices, it must satisfy the following options. */
2552 2552          if (cfg->cfg_n_if < 2) {
2553 2553                  USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
2554 2554                      "usbecm_get_descriptors: # of interfaces %d < 2",
2555 2555                      cfg->cfg_n_if);
2556 2556  
2557 2557                  return (USB_FAILURE);
2558 2558          }
2559 2559  
2560 2560          if (ecmp->ecm_data_if_no == 0 &&
2561 2561              slave_if != ecmp->ecm_data_if_no) {
2562 2562                  USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
2563 2563                      "usbecm_get_descriptors: Device has no call management "
2564 2564                      "descriptor and use Union Descriptor.");
2565 2565  
2566 2566                  ecmp->ecm_data_if_no = slave_if;
2567 2567          }
2568 2568  
2569 2569          if ((master_if != ecmp->ecm_ctrl_if_no) ||
2570 2570              (slave_if != ecmp->ecm_data_if_no)) {
2571 2571                  USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
2572 2572                      "usbecm_get_descriptors: control interface or "
2573 2573                      "data interface don't match.");
2574 2574  
2575 2575                  return (USB_FAILURE);
2576 2576          }
2577 2577  
2578 2578          if ((ecmp->ecm_ctrl_if_no >= cfg->cfg_n_if) ||
2579 2579              (ecmp->ecm_data_if_no >= cfg->cfg_n_if)) {
2580 2580                  USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
2581 2581                      "usbecm_get_descriptors: control interface %d or "
2582 2582                      "data interface %d out of range.",
2583 2583                      ecmp->ecm_ctrl_if_no, ecmp->ecm_data_if_no);
2584 2584  
2585 2585                  return (USB_FAILURE);
2586 2586          }
2587 2587  
2588 2588          /* ECM data interface has a minimal of two altsettings */
2589 2589          if (cfg->cfg_if[ecmp->ecm_data_if_no].if_n_alt < 2) {
2590 2590                  USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
2591 2591                      "usbecm_get_descriptors: elements in if_alt is %d,"
2592 2592                      " MUST >= 2", cfg->cfg_if[ecmp->ecm_ctrl_if_no].if_n_alt);
2593 2593  
2594 2594                  return (USB_FAILURE);
2595 2595          }
2596 2596  
2597 2597          /* control interface must have interrupt endpoint */
2598 2598          if ((ep_data = usb_lookup_ep_data(ecmp->ecm_dip, ecmp->ecm_dev_data,
2599 2599              ecmp->ecm_ctrl_if_no, 0, 0, USB_EP_ATTR_INTR,
2600 2600              USB_EP_DIR_IN)) == NULL) {
2601 2601                  USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
2602 2602                      "usbecm_get_descriptors: "
2603 2603                      "ctrl interface %d has no interrupt endpoint",
2604 2604                      ecmp->ecm_data_if_no);
2605 2605  
2606 2606                  return (USB_FAILURE);
2607 2607          }
2608 2608          ecmp->ecm_intr_ep = ep_data;
2609 2609  
2610 2610          /* data interface alt 1 must have bulk in and out(ECM v1.2,p5) */
2611 2611          if ((ep_data = usb_lookup_ep_data(ecmp->ecm_dip, ecmp->ecm_dev_data,
2612 2612              ecmp->ecm_data_if_no, 1, 0, USB_EP_ATTR_BULK,
2613 2613              USB_EP_DIR_IN)) == NULL) {
2614 2614                  USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
2615 2615                      "usbecm_get_descriptors: "
2616 2616                      "data interface %d has no bulk in endpoint",
2617 2617                      ecmp->ecm_data_if_no);
2618 2618  
2619 2619                  return (USB_FAILURE);
2620 2620          }
2621 2621          ecmp->ecm_bulk_in_ep = ep_data;
2622 2622  
2623 2623          if ((ep_data = usb_lookup_ep_data(ecmp->ecm_dip, ecmp->ecm_dev_data,
2624 2624              ecmp->ecm_data_if_no, 1, 0, USB_EP_ATTR_BULK,
2625 2625              USB_EP_DIR_OUT)) == NULL) {
2626 2626                  USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
2627 2627                      "usbecm_get_descriptors: "
2628 2628                      "data interface %d has no bulk out endpoint",
2629 2629                      ecmp->ecm_data_if_no);
2630 2630  
2631 2631                  return (USB_FAILURE);
2632 2632          }
2633 2633          ecmp->ecm_bulk_out_ep = ep_data;
2634 2634  
2635 2635          /* set default value for ethernet packet filter */
2636 2636          ecmp->ecm_pkt_flt = CDC_ECM_PKT_TYPE_DIRECTED;
2637 2637  
2638 2638          return (USB_SUCCESS);
2639 2639  }
2640 2640  
2641 2641  /* Generate IEEE802 style MAC address */
2642 2642  static void
2643 2643  generate_ether_addr(uint8_t *mac_addr)
2644 2644  {
2645 2645          (void) random_get_bytes(mac_addr, 6);
2646 2646          mac_addr [0] &= 0xfe;   /* unicast only */
2647 2647          mac_addr [0] |= 0x02;   /* set locally administered bit */
2648 2648  }
2649 2649  
2650 2650  /*
2651 2651   * Find a pair of bulk In/Out endpoints
2652 2652   */
2653 2653  int usbecm_find_bulk_in_out_eps(usbecm_state_t *ecmp,
2654 2654      uint16_t ifc, usb_if_data_t *intf)
2655 2655  {
2656 2656          uint16_t alt, alt_num;
2657 2657          usb_ep_data_t *intr_ep = NULL;
2658 2658          usb_ep_data_t *bulk_in, *bulk_out, *ep;
2659 2659  
2660 2660          alt_num = intf->if_n_alt;
2661 2661  
2662 2662          /*
2663 2663           * for the non-compatible devices, to make it simple, we
2664 2664           * suppose the devices have this kind of configuration:
2665 2665           *      INTR In EP(if exists) + BULK In + Bulk Out in the
2666 2666           *      same altsetting of the same interface
2667 2667           */
2668 2668          for (alt = 0; alt < alt_num; alt++) {
2669 2669                  /* search pair of bulk in/out EPs */
2670 2670                  if (((bulk_in = usb_lookup_ep_data(ecmp->ecm_dip,
2671 2671                      ecmp->ecm_dev_data, ifc, alt, 0,
2672 2672                      USB_EP_ATTR_BULK,
2673 2673                      USB_EP_DIR_IN)) == NULL) ||
2674 2674                      (bulk_out = usb_lookup_ep_data(ecmp->ecm_dip,
2675 2675                      ecmp->ecm_dev_data, ifc, alt, 0,
2676 2676                      USB_EP_ATTR_BULK,
2677 2677                      USB_EP_DIR_OUT)) == NULL) {
2678 2678  
2679 2679                          continue;
2680 2680                  }
2681 2681  
2682 2682                  /*
2683 2683                   * search interrupt pipe.
2684 2684                   */
2685 2685                  if ((ep = usb_lookup_ep_data(ecmp->ecm_dip,
2686 2686                      ecmp->ecm_dev_data, ifc, alt, 0,
2687 2687                      USB_EP_ATTR_INTR, USB_EP_DIR_IN)) != NULL) {
2688 2688                          intr_ep = ep;
2689 2689                  }
2690 2690  
2691 2691  
2692 2692                  ecmp->ecm_data_if_no = ifc;
2693 2693                  ecmp->ecm_data_if_alt = alt;
2694 2694                  ecmp->ecm_intr_ep = intr_ep;
2695 2695                  ecmp->ecm_ctrl_if_no = ifc;
2696 2696                  ecmp->ecm_bulk_in_ep = bulk_in;
2697 2697                  ecmp->ecm_bulk_out_ep = bulk_out;
2698 2698  
2699 2699                  return (USB_SUCCESS);
2700 2700          }
2701 2701  
2702 2702          return (USB_FAILURE);
2703 2703  }
2704 2704  
2705 2705  static int
2706 2706  usbecm_init_non_compatible_device(usbecm_state_t *ecmp)
2707 2707  {
2708 2708          usb_if_data_t *cur_if;
2709 2709          uint16_t if_num, i;
2710 2710  
2711 2711          /*
2712 2712           * If device don't conform to spec, search pairs of bulk in/out
2713 2713           * endpoints and fill related structure. We suppose this driver
2714 2714           * is bound to a interface.
2715 2715           */
2716 2716          cur_if = ecmp->ecm_dev_data->dev_curr_cfg->cfg_if;
2717 2717          if_num = ecmp->ecm_dev_data->dev_curr_cfg->cfg_n_if;
2718 2718  
2719 2719          /* search each interface which have bulk in and out */
2720 2720          for (i = 0; i < if_num; i++) {
2721 2721                  if (usbecm_find_bulk_in_out_eps(ecmp, i,
2722 2722                      cur_if) == USB_SUCCESS) {
2723 2723  
2724 2724                          break;
2725 2725                  }
2726 2726                  cur_if++;
2727 2727          }
2728 2728  
2729 2729          USB_DPRINTF_L4(PRINT_MASK_ATTA, ecmp->ecm_lh,
2730 2730              "usbecm_init_non_compatible_device: ctrl_if=%d,"
2731 2731              " data_if=%d, alt=%d", ecmp->ecm_ctrl_if_no,
2732 2732              ecmp->ecm_data_if_no, ecmp->ecm_data_if_alt);
2733 2733  
2734 2734          return (USB_SUCCESS);
2735 2735  }
2736 2736  
2737 2737  static boolean_t
2738 2738  usbecm_is_compatible(usbecm_state_t *ecmp)
2739 2739  {
2740 2740          usb_cfg_data_t *cfg_data;
2741 2741          usb_if_data_t *intf;
2742 2742          usb_alt_if_data_t *alt;
2743 2743          int alt_num, if_num, cfg_num;
2744 2744          int i, j, cfg_index;
2745 2745  
2746 2746          cfg_num = ecmp->ecm_dev_data->dev_n_cfg;
2747 2747          USB_DPRINTF_L3(PRINT_MASK_ATTA, ecmp->ecm_lh,
2748 2748              "usbecm_is_compatible: entry, cfg_num=%d", cfg_num);
2749 2749  
2750 2750          for (cfg_index = 0; cfg_index < cfg_num; cfg_index++) {
2751 2751                  cfg_data = &(ecmp->ecm_dev_data->dev_cfg[cfg_index]);
2752 2752  
2753 2753                  USB_DPRINTF_L3(PRINT_MASK_ATTA, ecmp->ecm_lh,
2754 2754                      "usbecm_is_compatible: cfg_index=%d, value=%d",
2755 2755                      cfg_index, cfg_data->cfg_descr.bConfigurationValue);
2756 2756  
2757 2757                  intf = cfg_data->cfg_if;
2758 2758                  if_num = cfg_data->cfg_n_if;
2759 2759  
2760 2760                  for (i = 0; i < if_num; i++) {
2761 2761                          alt_num = intf->if_n_alt;
2762 2762                          for (j = 0; j < alt_num; j++) {
2763 2763                          alt = &intf->if_alt[j];
2764 2764                          if ((alt->altif_descr.bInterfaceClass == 0x02) &&
2765 2765                              (alt->altif_descr.bInterfaceSubClass == 0x06)) {
2766 2766                                  ecmp->ecm_cfg_index = cfg_index;
2767 2767  
2768 2768                                  USB_DPRINTF_L3(PRINT_MASK_ATTA, ecmp->ecm_lh,
2769 2769                                      "usbecm_is_compatible: cfg_index=%d",
2770 2770                                      cfg_index);
2771 2771  
2772 2772                                  return (B_TRUE);
2773 2773                          }
2774 2774                          }
2775 2775                          intf++;
2776 2776                  }
2777 2777          }
2778 2778  
2779 2779          return (B_FALSE);
2780 2780  }
2781 2781  
2782 2782  
2783 2783  static int
2784 2784  usbecm_usb_init(usbecm_state_t *ecmp)
2785 2785  {
2786 2786  
2787 2787          if (usb_client_attach(ecmp->ecm_dip, USBDRV_VERSION, 0) !=
2788 2788              USB_SUCCESS) {
2789 2789                  USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
2790 2790                  "usbecm_usb_init: fail to attach");
2791 2791  
2792 2792                  return (USB_FAILURE);
2793 2793          }
2794 2794  
2795 2795          /* Get the configuration information of device */
2796 2796          if (usb_get_dev_data(ecmp->ecm_dip, &ecmp->ecm_dev_data,
2797 2797              USB_PARSE_LVL_ALL, 0) != USB_SUCCESS) {
2798 2798                  USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
2799 2799                  "usbecm_usb_init: fail to get_dev_data");
2800 2800  
2801 2801                  return (USB_FAILURE);
2802 2802          }
2803 2803          ecmp->ecm_def_ph = ecmp->ecm_dev_data->dev_default_ph;
2804 2804          ecmp->ecm_dev_state = USB_DEV_ONLINE;
2805 2805  
2806 2806          mutex_init(&ecmp->ecm_mutex, NULL, MUTEX_DRIVER,
2807 2807              ecmp->ecm_dev_data->dev_iblock_cookie);
2808 2808  
2809 2809          if ((strcmp(ddi_binding_name(ecmp->ecm_dip),
2810 2810              "usbif,class2.6") == 0) ||
2811 2811              ((strcmp(ddi_binding_name(ecmp->ecm_dip),
2812 2812              "usb,class2.6.0") == 0))) {
2813 2813                  USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
2814 2814                      "usbecm_usb_init: A CDC ECM device is attached");
2815 2815                  ecmp->ecm_compatibility = B_TRUE;
2816 2816          } else if (usb_owns_device(ecmp->ecm_dip) &&
2817 2817              usbecm_is_compatible(ecmp)) {
2818 2818                  /*
2819 2819                   * Current Sun SP ECM device has two configurations. Hence
2820 2820                   * USBA doesn't create interface level compatible names
2821 2821                   * for it, see usba_ready_device_node(). We have to check
2822 2822                   * manually to see if compatible interfaces exist, when
2823 2823                   * the driver owns the entire device.
2824 2824                   */
2825 2825                  USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
2826 2826                      "usbecm_usb_init: A CDC ECM device is attached");
2827 2827                  ecmp->ecm_compatibility = B_TRUE;
2828 2828          } else {
2829 2829                  USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
2830 2830                      "usbecm_usb_init: A nonstandard device is attached to "
2831 2831                      "usbecm(7D) driver. This device doesn't conform to "
2832 2832                      "usb cdc spec.");
2833 2833                  ecmp->ecm_compatibility = B_FALSE;
2834 2834  
2835 2835                  /* generate a random MAC addr */
2836 2836                  generate_ether_addr(ecmp->ecm_srcaddr);
2837 2837          }
2838 2838  
2839 2839          if ((ecmp->ecm_compatibility == B_TRUE) &&
2840 2840              (usbecm_get_descriptors(ecmp) != USB_SUCCESS)) {
2841 2841                  USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
2842 2842                      "usbecm_usb_init: A compatible device is attached, but "
2843 2843                      "fail to get standard descriptors");
2844 2844  
2845 2845                  return (USB_FAILURE);
2846 2846          }
2847 2847  
2848 2848          if (ecmp->ecm_compatibility == B_FALSE) {
2849 2849                  (void) usbecm_init_non_compatible_device(ecmp);
2850 2850          }
2851 2851  
2852 2852          /* Create power management components */
2853 2853          if (usbecm_create_pm_components(ecmp) != USB_SUCCESS) {
2854 2854                  USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
2855 2855                      "usbecm_usb_init: create pm components failed.");
2856 2856  
2857 2857                  return (USB_FAILURE);
2858 2858          }
2859 2859  
2860 2860          /* Register to get callbacks for USB events */
2861 2861          if (usb_register_event_cbs(ecmp->ecm_dip, &usbecm_events, 0)
2862 2862              != USB_SUCCESS) {
2863 2863                  USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
2864 2864                      "usbsecm_attach: register event callback failed.");
2865 2865  
2866 2866                  return (USB_FAILURE);
2867 2867          }
2868 2868          ecmp->ecm_init_flags |= USBECM_INIT_EVENTS;
2869 2869  
2870 2870  
2871 2871          /* Get max data size of bulk transfer */
2872 2872          if (usb_pipe_get_max_bulk_transfer_size(ecmp->ecm_dip,
2873 2873              &ecmp->ecm_xfer_sz) != USB_SUCCESS) {
2874 2874                  USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
2875 2875                      "usbsecm_ds_attach: get max size of transfer failed.");
2876 2876  
2877 2877                  return (USB_FAILURE);
2878 2878          }
2879 2879  
2880 2880  
2881 2881          ecmp->ecm_ser_acc = usb_init_serialization(ecmp->ecm_dip,
2882 2882              USB_INIT_SER_CHECK_SAME_THREAD);
2883 2883          ecmp->ecm_init_flags |= USBECM_INIT_SER;
2884 2884  
2885 2885          return (USB_SUCCESS);
2886 2886  }
2887 2887  
2888 2888  
2889 2889  /*
2890 2890   * Open operation pipes. Each ECM device should have Bulk In, Bulk Out
2891 2891   * and Interrupt In endpoints
2892 2892   */
2893 2893  static int
2894 2894  usbecm_open_pipes(usbecm_state_t *ecmp)
2895 2895  {
2896 2896          int             rval = USB_SUCCESS;
2897 2897          usb_ep_data_t   *in_data, *out_data, *intr_pipe;
2898 2898          usb_pipe_policy_t policy;
2899 2899          int             altif;
2900 2900  
2901 2901          ASSERT(!mutex_owned(&ecmp->ecm_mutex));
2902 2902  
2903 2903          USB_DPRINTF_L4(PRINT_MASK_OPEN, ecmp->ecm_lh,
2904 2904              "usbsecm_open_pipes: ecmp = 0x%p", (void *)ecmp);
2905 2905  
2906 2906          if (ecmp->ecm_compatibility == B_TRUE) {
2907 2907          /* compatible device has minimum of 2 altsetting, select alt 1 */
2908 2908                  altif = 1;
2909 2909          } else {
2910 2910                  altif = ecmp->ecm_data_if_alt;
2911 2911          }
2912 2912          intr_pipe = ecmp->ecm_intr_ep;
2913 2913          in_data = ecmp->ecm_bulk_in_ep;
2914 2914          out_data = ecmp->ecm_bulk_out_ep;
2915 2915  
2916 2916          /* Bulk in and out must exist simultaneously. */
2917 2917          if ((in_data == NULL) || (out_data == NULL)) {
2918 2918                  USB_DPRINTF_L2(PRINT_MASK_OPEN, ecmp->ecm_lh,
2919 2919                      "usbsecm_open_pipes: look up bulk pipe failed in "
2920 2920                      "interface %d ",
2921 2921                      ecmp->ecm_data_if_no);
2922 2922  
2923 2923                  return (USB_FAILURE);
2924 2924          }
2925 2925          /*
2926 2926           * If device conform to ecm spec, it must have an interrupt pipe
2927 2927           * for this device.
2928 2928           */
2929 2929          if (ecmp->ecm_compatibility == B_TRUE && intr_pipe == NULL) {
2930 2930                  USB_DPRINTF_L2(PRINT_MASK_OPEN, ecmp->ecm_lh,
2931 2931                      "usbecm_open_pipes: look up interrupt pipe failed in "
2932 2932                      "interface %d", ecmp->ecm_ctrl_if_no);
2933 2933  
2934 2934                  return (USB_FAILURE);
2935 2935          }
2936 2936  
2937 2937          USB_DPRINTF_L3(PRINT_MASK_OPEN, ecmp->ecm_lh,
2938 2938              "usbsecm_open_pipes: open intr %02x, bulkin %02x bulkout %02x",
2939 2939              intr_pipe?intr_pipe->ep_descr.bEndpointAddress:0,
2940 2940              in_data->ep_descr.bEndpointAddress,
2941 2941              out_data->ep_descr.bEndpointAddress);
2942 2942  
2943 2943          USB_DPRINTF_L3(PRINT_MASK_OPEN, ecmp->ecm_lh,
2944 2944              "usbsecm_open_pipes: set data if(%d) alt(%d) ",
2945 2945              ecmp->ecm_data_if_no, altif);
2946 2946  
2947 2947          if ((rval = usb_set_alt_if(ecmp->ecm_dip, ecmp->ecm_data_if_no,
2948 2948              altif, USB_FLAGS_SLEEP, NULL, NULL)) != USB_SUCCESS) {
2949 2949                  USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
2950 2950                      "usbecm_open_pipes: set alternate failed (%d)",
2951 2951                      rval);
2952 2952  
2953 2953                  return (rval);
2954 2954          }
2955 2955  
2956 2956          policy.pp_max_async_reqs = 2;
2957 2957  
2958 2958          /* Open bulk in endpoint */
2959 2959          if (usb_pipe_open(ecmp->ecm_dip, &in_data->ep_descr, &policy,
2960 2960              USB_FLAGS_SLEEP, &ecmp->ecm_bulkin_ph) != USB_SUCCESS) {
2961 2961                  USB_DPRINTF_L2(PRINT_MASK_OPEN, ecmp->ecm_lh,
2962 2962                      "usbecm_open_pipes: open bulkin pipe failed!");
2963 2963  
2964 2964                  return (USB_FAILURE);
2965 2965          }
2966 2966  
2967 2967          /* Open bulk out endpoint */
2968 2968          if (usb_pipe_open(ecmp->ecm_dip, &out_data->ep_descr, &policy,
2969 2969              USB_FLAGS_SLEEP, &ecmp->ecm_bulkout_ph) != USB_SUCCESS) {
2970 2970                  USB_DPRINTF_L2(PRINT_MASK_OPEN, ecmp->ecm_lh,
2971 2971                      "usbecm_open_pipes: open bulkout pipe failed!");
2972 2972  
2973 2973                  usb_pipe_close(ecmp->ecm_dip, ecmp->ecm_bulkin_ph,
2974 2974                      USB_FLAGS_SLEEP, NULL, NULL);
2975 2975  
2976 2976                  return (USB_FAILURE);
2977 2977          }
2978 2978  
2979 2979          /* Open interrupt endpoint if found. */
2980 2980          if (intr_pipe != NULL) {
2981 2981                  if (usb_pipe_open(ecmp->ecm_dip, &intr_pipe->ep_descr, &policy,
2982 2982                      USB_FLAGS_SLEEP, &ecmp->ecm_intr_ph) != USB_SUCCESS) {
2983 2983                          USB_DPRINTF_L2(PRINT_MASK_OPEN, ecmp->ecm_lh,
2984 2984                              "usbecm_open_pipes: "
2985 2985                              "open intr pipe failed");
2986 2986  
2987 2987                          usb_pipe_close(ecmp->ecm_dip, ecmp->ecm_bulkin_ph,
2988 2988                              USB_FLAGS_SLEEP, NULL, NULL);
2989 2989                          usb_pipe_close(ecmp->ecm_dip, ecmp->ecm_bulkout_ph,
2990 2990                              USB_FLAGS_SLEEP, NULL, NULL);
2991 2991  
2992 2992                          return (USB_FAILURE);
2993 2993                  }
2994 2994          }
2995 2995  
2996 2996          /* initialize the pipe related data */
2997 2997          mutex_enter(&ecmp->ecm_mutex);
2998 2998          ecmp->ecm_bulkin_sz = in_data->ep_descr.wMaxPacketSize;
2999 2999          ecmp->ecm_bulkin_state = USBECM_PIPE_IDLE;
3000 3000          ecmp->ecm_bulkout_state = USBECM_PIPE_IDLE;
3001 3001          if (ecmp->ecm_intr_ph != NULL) {
3002 3002                  ecmp->ecm_intr_state = USBECM_PIPE_IDLE;
3003 3003          }
3004 3004          mutex_exit(&ecmp->ecm_mutex);
3005 3005  
3006 3006          if (ecmp->ecm_intr_ph != NULL) {
3007 3007  
3008 3008                  usbecm_pipe_start_polling(ecmp);
3009 3009          }
3010 3010  
3011 3011          USB_DPRINTF_L4(PRINT_MASK_OPEN, ecmp->ecm_lh,
3012 3012              "usbsecm_open_pipes: end");
3013 3013  
3014 3014          return (rval);
3015 3015  }
3016 3016  
3017 3017  
3018 3018  /*
3019 3019   * usbsecm_close_pipes:
3020 3020   *      Close pipes
3021 3021   *      Each device could include three pipes: bulk in, bulk out and interrupt.
3022 3022   */
3023 3023  static void
3024 3024  usbecm_close_pipes(usbecm_state_t *ecmp)
3025 3025  {
3026 3026  
3027 3027          mutex_enter(&ecmp->ecm_mutex);
3028 3028  
3029 3029          USB_DPRINTF_L4(PRINT_MASK_CLOSE, ecmp->ecm_lh,
3030 3030              "usbsecm_close_pipes: ecm_bulkin_state = %d",
3031 3031              ecmp->ecm_bulkin_state);
3032 3032  
3033 3033          /*
3034 3034           * Check the status of the pipes. If pipe is closing or closed,
3035 3035           * return directly.
3036 3036           */
3037 3037          if ((ecmp->ecm_bulkin_state == USBECM_PIPE_CLOSED) ||
3038 3038              (ecmp->ecm_bulkin_state == USBECM_PIPE_CLOSING)) {
3039 3039                  USB_DPRINTF_L2(PRINT_MASK_CLOSE, ecmp->ecm_lh,
3040 3040                      "usbsecm_close_pipes: pipe is closing or has closed");
3041 3041                  mutex_exit(&ecmp->ecm_mutex);
3042 3042  
3043 3043                  return;
3044 3044          }
3045 3045  
3046 3046          ecmp->ecm_bulkin_state = USBECM_PIPE_CLOSING;
3047 3047          mutex_exit(&ecmp->ecm_mutex);
3048 3048  
3049 3049          /* reset the data interface's altsetting to 0 */
3050 3050          if ((ecmp->ecm_dev_state == USB_DEV_ONLINE) &&
3051 3051              (usb_set_alt_if(ecmp->ecm_dip, ecmp->ecm_data_if_no,
3052 3052              0, USB_FLAGS_SLEEP, NULL, NULL) != USB_SUCCESS)) {
3053 3053                  USB_DPRINTF_L2(PRINT_MASK_ATTA, ecmp->ecm_lh,
3054 3054                      "usbecm_close_pipes: reset alternate failed ");
3055 3055          }
3056 3056  
3057 3057          /* Close pipes */
3058 3058          usb_pipe_reset(ecmp->ecm_dip, ecmp->ecm_bulkin_ph,
3059 3059              USB_FLAGS_SLEEP, NULL, 0);
3060 3060          usb_pipe_close(ecmp->ecm_dip, ecmp->ecm_bulkin_ph,
3061 3061              USB_FLAGS_SLEEP, NULL, 0);
3062 3062          usb_pipe_close(ecmp->ecm_dip, ecmp->ecm_bulkout_ph,
3063 3063              USB_FLAGS_SLEEP, NULL, 0);
3064 3064  
3065 3065          if (ecmp->ecm_intr_ph != NULL) {
3066 3066                  usb_pipe_stop_intr_polling(ecmp->ecm_intr_ph,
3067 3067                      USB_FLAGS_SLEEP);
3068 3068                  usb_pipe_close(ecmp->ecm_dip, ecmp->ecm_intr_ph,
3069 3069                      USB_FLAGS_SLEEP, NULL, 0);
3070 3070          }
3071 3071  
3072 3072          mutex_enter(&ecmp->ecm_mutex);
3073 3073          /* Reset the status of pipes to closed */
3074 3074          ecmp->ecm_bulkin_state = USBECM_PIPE_CLOSED;
3075 3075          ecmp->ecm_bulkin_ph = NULL;
3076 3076          ecmp->ecm_bulkout_state = USBECM_PIPE_CLOSED;
3077 3077          ecmp->ecm_bulkout_ph = NULL;
3078 3078          if (ecmp->ecm_intr_ph != NULL) {
3079 3079                  ecmp->ecm_intr_state = USBECM_PIPE_CLOSED;
3080 3080                  ecmp->ecm_intr_ph = NULL;
3081 3081          }
3082 3082  
3083 3083          mutex_exit(&ecmp->ecm_mutex);
3084 3084  
3085 3085          USB_DPRINTF_L4(PRINT_MASK_CLOSE, ecmp->ecm_lh,
3086 3086              "usbsecm_close_pipes: pipes have been closed.");
3087 3087  }
3088 3088  
3089 3089  
3090 3090  static int
3091 3091  usbecm_ctrl_write(usbecm_state_t *ecmp, uchar_t request,
3092 3092      uint16_t value, mblk_t **data)
3093 3093  {
3094 3094          usb_ctrl_setup_t setup;
3095 3095          usb_cb_flags_t  cb_flags;
3096 3096          usb_cr_t        cr;
3097 3097          int             rval;
3098 3098  
3099 3099          USB_DPRINTF_L4(PRINT_MASK_ALL, ecmp->ecm_lh,
3100 3100              "usbecm_ctrl_write: ");
3101 3101  
3102 3102          /* initialize the control request. */
3103 3103          setup.bmRequestType = USB_DEV_REQ_HOST_TO_DEV |
3104 3104              USB_DEV_REQ_TYPE_CLASS | USB_DEV_REQ_RCPT_IF;
3105 3105          setup.bRequest = request;
3106 3106          setup.wValue = value;
3107 3107          setup.wIndex = ecmp->ecm_ctrl_if_no;
3108 3108          setup.wLength = ((data != NULL) && (*data != NULL)) ? MBLKL(*data) : 0;
3109 3109          setup.attrs = 0;
3110 3110  
3111 3111          rval = usb_pipe_ctrl_xfer_wait(ecmp->ecm_def_ph, &setup, data,
3112 3112              &cr, &cb_flags, 0);
3113 3113  
3114 3114          USB_DPRINTF_L4(PRINT_MASK_ALL, ecmp->ecm_lh,
3115 3115              "usbecm_ctrl_write: rval = %d", rval);
3116 3116  
3117 3117          return (rval);
3118 3118  }
3119 3119  
3120 3120  static int
3121 3121  usbecm_ctrl_read(usbecm_state_t *ecmp, uchar_t request,
3122 3122      uint16_t value, mblk_t **data, int len)
3123 3123  {
3124 3124          usb_ctrl_setup_t setup;
3125 3125          usb_cb_flags_t  cb_flags;
3126 3126          usb_cr_t        cr;
3127 3127  
3128 3128          USB_DPRINTF_L4(PRINT_MASK_ALL, ecmp->ecm_lh,
3129 3129              "usbecm_ctrl_read: ");
3130 3130  
3131 3131          /* initialize the control request. */
3132 3132          setup.bmRequestType = USB_DEV_REQ_DEV_TO_HOST |
3133 3133              USB_DEV_REQ_TYPE_CLASS | USB_DEV_REQ_RCPT_IF;
3134 3134          setup.bRequest = request;
3135 3135          setup.wValue = value;
3136 3136          setup.wIndex = ecmp->ecm_ctrl_if_no;
3137 3137          setup.wLength = (uint16_t)len;
3138 3138          setup.attrs = 0;
3139 3139  
3140 3140          return (usb_pipe_ctrl_xfer_wait(ecmp->ecm_def_ph, &setup, data,
3141 3141              &cr, &cb_flags, 0));
3142 3142  }
3143 3143  
3144 3144  /* Get specific statistic data from device */
3145 3145  static int
3146 3146  usbecm_get_statistics(usbecm_state_t *ecmp, uint32_t fs, uint32_t *stat_data)
3147 3147  {
3148 3148          mblk_t *data = NULL;
3149 3149          uint32_t stat;
3150 3150  
3151 3151          /* first check to see if this stat is collected by device */
3152 3152          if ((ecmp->ecm_compatibility == B_TRUE) &&
3153 3153              (ecmp->ecm_desc.bmEthernetStatistics & ECM_STAT_CAP_MASK(fs))) {
3154 3154                  if (usbecm_ctrl_read(ecmp, CDC_ECM_GET_ETH_STAT,
3155 3155                      ecmp->ecm_ctrl_if_no, &data, 4) != USB_SUCCESS) {
3156 3156  
3157 3157                          return (USB_FAILURE);
3158 3158                  }
3159 3159                  stat = (data->b_rptr[3] << 24) | (data->b_rptr[2] << 16) |
3160 3160                      (data->b_rptr[1] << 8) | (data->b_rptr[0]);
3161 3161                  *stat_data = stat;
3162 3162  
3163 3163                  freemsg(data);
3164 3164  
3165 3165                  return (USB_SUCCESS);
3166 3166          }
3167 3167  
3168 3168          return (USB_FAILURE);
3169 3169  }
  
    | 
      ↓ open down ↓ | 
    2932 lines elided | 
    
      ↑ open up ↑ | 
  
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX