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