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