Print this page
7127 remove -Wno-missing-braces from Makefile.uts
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/io/usb/usb_ia/usb_ia.c
+++ new/usr/src/uts/common/io/usb/usb_ia/usb_ia.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 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 24 */
25 25 /*
26 26 * Copyright 2012 Garrett D'Amore <garrett@damore.org>. All rights reserved.
27 27 */
28 28
29 29
30 30 /*
31 31 * usb interface association driver
32 32 *
33 33 * this driver attempts to the interface association node and
34 34 * creates/manages child nodes for the included interfaces.
35 35 */
36 36
37 37 #if defined(lint) && !defined(DEBUG)
38 38 #define DEBUG 1
39 39 #endif
40 40 #include <sys/usb/usba/usbai_version.h>
41 41 #include <sys/usb/usba.h>
42 42 #include <sys/usb/usba/usba_types.h>
43 43 #include <sys/usb/usba/usba_impl.h>
44 44 #include <sys/usb/usb_ia/usb_iavar.h>
45 45
46 46 /* Debugging support */
47 47 uint_t usb_ia_errlevel = USB_LOG_L4;
48 48 uint_t usb_ia_errmask = (uint_t)DPRINT_MASK_ALL;
49 49 uint_t usb_ia_instance_debug = (uint_t)-1;
50 50 uint_t usb_ia_bus_config_debug = 0;
51 51
52 52 _NOTE(DATA_READABLE_WITHOUT_LOCK(usb_ia_errlevel))
53 53 _NOTE(DATA_READABLE_WITHOUT_LOCK(usb_ia_errmask))
54 54 _NOTE(DATA_READABLE_WITHOUT_LOCK(usb_ia_instance_debug))
55 55
56 56 _NOTE(SCHEME_PROTECTS_DATA("unique", msgb))
57 57 _NOTE(SCHEME_PROTECTS_DATA("unique", dev_info))
58 58 _NOTE(SCHEME_PROTECTS_DATA("unique", usb_pipe_policy))
59 59
60 60 static struct cb_ops usb_ia_cb_ops = {
61 61 nodev, /* open */
62 62 nodev, /* close */
63 63 nodev, /* strategy */
64 64 nodev, /* print */
65 65 nodev, /* dump */
66 66 nodev, /* read */
67 67 nodev, /* write */
68 68 nodev, /* ioctl */
69 69 nodev, /* devmap */
70 70 nodev, /* mmap */
71 71 nodev, /* segmap */
72 72 nochpoll, /* poll */
73 73 ddi_prop_op, /* prop_op */
74 74 NULL, /* aread */
75 75 D_MP
76 76 };
77 77
78 78 static int usb_ia_busop_get_eventcookie(dev_info_t *dip,
79 79 dev_info_t *rdip,
80 80 char *eventname,
81 81 ddi_eventcookie_t *cookie);
82 82 static int usb_ia_busop_add_eventcall(dev_info_t *dip,
83 83 dev_info_t *rdip,
84 84 ddi_eventcookie_t cookie,
85 85 void (*callback)(dev_info_t *dip,
86 86 ddi_eventcookie_t cookie, void *arg,
87 87 void *bus_impldata),
88 88 void *arg, ddi_callback_id_t *cb_id);
89 89 static int usb_ia_busop_remove_eventcall(dev_info_t *dip,
90 90 ddi_callback_id_t cb_id);
91 91 static int usb_ia_busop_post_event(dev_info_t *dip,
92 92 dev_info_t *rdip,
93 93 ddi_eventcookie_t cookie,
94 94 void *bus_impldata);
95 95 static int usb_ia_bus_config(dev_info_t *dip,
96 96 uint_t flag,
97 97 ddi_bus_config_op_t op,
98 98 void *arg,
99 99 dev_info_t **child);
100 100 static int usb_ia_bus_unconfig(dev_info_t *dip,
101 101 uint_t flag,
102 102 ddi_bus_config_op_t op,
103 103 void *arg);
104 104
105 105 /*
106 106 * autoconfiguration data and routines.
107 107 */
108 108 static int usb_ia_info(dev_info_t *, ddi_info_cmd_t,
109 109 void *, void **);
110 110 static int usb_ia_attach(dev_info_t *, ddi_attach_cmd_t);
111 111 static int usb_ia_detach(dev_info_t *, ddi_detach_cmd_t);
112 112
113 113 /* other routines */
114 114 static void usb_ia_create_pm_components(dev_info_t *, usb_ia_t *);
115 115 static int usb_ia_bus_ctl(dev_info_t *, dev_info_t *,
116 116 ddi_ctl_enum_t, void *, void *);
117 117 static int usb_ia_power(dev_info_t *, int, int);
118 118 static int usb_ia_restore_device_state(dev_info_t *, usb_ia_t *);
119 119 static usb_ia_t *usb_ia_obtain_state(dev_info_t *);
120 120 static void usb_ia_event_cb(dev_info_t *, ddi_eventcookie_t, void *, void *);
121 121
122 122 /* prototypes */
123 123 static void usb_ia_create_children(usb_ia_t *);
124 124 static int usb_ia_cleanup(usb_ia_t *);
125 125
126 126 /*
127 127 * Busops vector
128 128 */
129 129 static struct bus_ops usb_ia_busops = {
130 130 BUSO_REV,
131 131 nullbusmap, /* bus_map */
132 132 NULL, /* bus_get_intrspec */
133 133 NULL, /* bus_add_intrspec */
134 134 NULL, /* bus_remove_intrspec */
135 135 NULL, /* XXXX bus_map_fault */
136 136 NULL, /* bus_dma_map */
137 137 ddi_dma_allochdl,
138 138 ddi_dma_freehdl,
139 139 ddi_dma_bindhdl,
140 140 ddi_dma_unbindhdl,
141 141 ddi_dma_flush,
142 142 ddi_dma_win,
143 143 ddi_dma_mctl, /* bus_dma_ctl */
144 144 usb_ia_bus_ctl, /* bus_ctl */
145 145 ddi_bus_prop_op, /* bus_prop_op */
146 146 usb_ia_busop_get_eventcookie,
147 147 usb_ia_busop_add_eventcall,
148 148 usb_ia_busop_remove_eventcall,
149 149 usb_ia_busop_post_event, /* bus_post_event */
150 150 NULL, /* bus_intr_ctl */
151 151 usb_ia_bus_config, /* bus_config */
152 152 usb_ia_bus_unconfig, /* bus_unconfig */
153 153 NULL, /* bus_fm_init */
154 154 NULL, /* bus_fm_fini */
155 155 NULL, /* bus_fm_access_enter */
156 156 NULL, /* bus_fm_access_exit */
157 157 NULL /* bus_power */
158 158 };
159 159
160 160
161 161 static struct dev_ops usb_ia_ops = {
162 162 DEVO_REV, /* devo_rev, */
163 163 0, /* refcnt */
164 164 usb_ia_info, /* info */
165 165 nulldev, /* identify */
166 166 nulldev, /* probe */
167 167 usb_ia_attach, /* attach */
168 168 usb_ia_detach, /* detach */
169 169 nodev, /* reset */
170 170 &usb_ia_cb_ops, /* driver operations */
171 171 &usb_ia_busops, /* bus operations */
172 172 usb_ia_power, /* power */
↓ open down ↓ |
172 lines elided |
↑ open up ↑ |
173 173 ddi_quiesce_not_needed, /* devo_quiesce */
174 174 };
175 175
176 176 static struct modldrv modldrv = {
177 177 &mod_driverops, /* Type of module. This one is a driver */
178 178 "USB Interface Association Driver", /* Name of the module. */
179 179 &usb_ia_ops, /* driver ops */
180 180 };
181 181
182 182 static struct modlinkage modlinkage = {
183 - MODREV_1, (void *)&modldrv, NULL
183 + MODREV_1, { (void *)&modldrv, NULL }
184 184 };
185 185
186 186 #define USB_IA_INITIAL_SOFT_SPACE 4
187 187 static void *usb_ia_statep;
188 188
189 189 /*
190 190 * event definition
191 191 */
192 192 static ndi_event_definition_t usb_ia_ndi_event_defs[] = {
193 193 {USBA_EVENT_TAG_HOT_REMOVAL, DDI_DEVI_REMOVE_EVENT, EPL_KERNEL,
194 194 NDI_EVENT_POST_TO_ALL},
195 195 {USBA_EVENT_TAG_HOT_INSERTION, DDI_DEVI_INSERT_EVENT, EPL_KERNEL,
196 196 NDI_EVENT_POST_TO_ALL},
197 197 {USBA_EVENT_TAG_POST_RESUME, USBA_POST_RESUME_EVENT, EPL_KERNEL,
198 198 NDI_EVENT_POST_TO_ALL},
199 199 {USBA_EVENT_TAG_PRE_SUSPEND, USBA_PRE_SUSPEND_EVENT, EPL_KERNEL,
200 200 NDI_EVENT_POST_TO_ALL}
201 201 };
202 202
203 203 #define USB_IA_N_NDI_EVENTS \
204 204 (sizeof (usb_ia_ndi_event_defs) / sizeof (ndi_event_definition_t))
205 205
206 206 static ndi_event_set_t usb_ia_ndi_events = {
207 207 NDI_EVENTS_REV1, USB_IA_N_NDI_EVENTS, usb_ia_ndi_event_defs};
208 208
209 209
210 210 /*
211 211 * standard driver entry points
212 212 */
213 213 int
214 214 _init(void)
215 215 {
216 216 int rval;
217 217
218 218 rval = ddi_soft_state_init(&usb_ia_statep, sizeof (struct usb_ia),
219 219 USB_IA_INITIAL_SOFT_SPACE);
220 220 if (rval != 0) {
221 221 return (rval);
222 222 }
223 223
224 224 if ((rval = mod_install(&modlinkage)) != 0) {
225 225 ddi_soft_state_fini(&usb_ia_statep);
226 226 return (rval);
227 227 }
228 228
229 229 return (rval);
230 230 }
231 231
232 232
233 233 int
234 234 _fini(void)
235 235 {
236 236 int rval;
237 237
238 238 rval = mod_remove(&modlinkage);
239 239
240 240 if (rval) {
241 241 return (rval);
242 242 }
243 243
244 244 ddi_soft_state_fini(&usb_ia_statep);
245 245
246 246 return (rval);
247 247 }
248 248
249 249
250 250 int
251 251 _info(struct modinfo *modinfop)
252 252 {
253 253 return (mod_info(&modlinkage, modinfop));
254 254 }
255 255
256 256
257 257 /*ARGSUSED*/
258 258 static int
259 259 usb_ia_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
260 260 {
261 261 usb_ia_t *usb_ia;
262 262 int instance = getminor((dev_t)arg);
263 263 int error = DDI_FAILURE;
264 264
265 265 switch (infocmd) {
266 266 case DDI_INFO_DEVT2DEVINFO:
267 267 if ((usb_ia = ddi_get_soft_state(usb_ia_statep,
268 268 instance)) != NULL) {
269 269 *result = (void *)usb_ia->ia_dip;
270 270 if (*result != NULL) {
271 271 error = DDI_SUCCESS;
272 272 }
273 273 } else {
274 274 *result = NULL;
275 275 }
276 276 break;
277 277
278 278 case DDI_INFO_DEVT2INSTANCE:
279 279 *result = (void *)(intptr_t)instance;
280 280 error = DDI_SUCCESS;
281 281 break;
282 282 default:
283 283 break;
284 284 }
285 285
286 286 return (error);
287 287 }
288 288
289 289
290 290 /*
291 291 * child post attach/detach notification
292 292 */
293 293 static void
294 294 usb_ia_post_attach(usb_ia_t *usb_ia, uint8_t ifno, struct attachspec *as)
295 295 {
296 296 USB_DPRINTF_L4(DPRINT_MASK_PM, usb_ia->ia_log_handle,
297 297 "usb_ia_post_attach: ifno = %d result = %d", ifno, as->result);
298 298
299 299 }
300 300
301 301
302 302 static void
303 303 usb_ia_post_detach(usb_ia_t *usb_ia, uint8_t ifno, struct detachspec *ds)
304 304 {
305 305 USB_DPRINTF_L4(DPRINT_MASK_PM, usb_ia->ia_log_handle,
306 306 "usb_ia_post_detach: ifno = %d result = %d", ifno, ds->result);
307 307
308 308 }
309 309
310 310
311 311 /*
312 312 * bus ctl support. we handle notifications here and the
313 313 * rest goes up to root hub/hcd
314 314 */
315 315 /*ARGSUSED*/
316 316 static int
317 317 usb_ia_bus_ctl(dev_info_t *dip,
318 318 dev_info_t *rdip,
319 319 ddi_ctl_enum_t op,
320 320 void *arg,
321 321 void *result)
322 322 {
323 323 usba_device_t *hub_usba_device = usba_get_usba_device(rdip);
324 324 dev_info_t *root_hub_dip = hub_usba_device->usb_root_hub_dip;
325 325 usb_ia_t *usb_ia;
326 326 struct attachspec *as;
327 327 struct detachspec *ds;
328 328
329 329 usb_ia = usb_ia_obtain_state(dip);
330 330
331 331 USB_DPRINTF_L4(DPRINT_MASK_PM, usb_ia->ia_log_handle,
332 332 "usb_ia_bus_ctl:\n\t"
333 333 "dip = 0x%p, rdip = 0x%p, op = 0x%x, arg = 0x%p",
334 334 (void *)dip, (void *)rdip, op, arg);
335 335
336 336 switch (op) {
337 337 case DDI_CTLOPS_ATTACH:
338 338 as = (struct attachspec *)arg;
339 339
340 340 switch (as->when) {
341 341 case DDI_PRE :
342 342 /* nothing to do basically */
343 343 USB_DPRINTF_L2(DPRINT_MASK_PM, usb_ia->ia_log_handle,
344 344 "DDI_PRE DDI_CTLOPS_ATTACH");
345 345 break;
346 346 case DDI_POST :
347 347 usb_ia_post_attach(usb_ia, usba_get_ifno(rdip),
348 348 (struct attachspec *)arg);
349 349 break;
350 350 }
351 351
352 352 break;
353 353 case DDI_CTLOPS_DETACH:
354 354 ds = (struct detachspec *)arg;
355 355
356 356 switch (ds->when) {
357 357 case DDI_PRE :
358 358 /* nothing to do basically */
359 359 USB_DPRINTF_L2(DPRINT_MASK_PM, usb_ia->ia_log_handle,
360 360 "DDI_PRE DDI_CTLOPS_DETACH");
361 361 break;
362 362 case DDI_POST :
363 363 usb_ia_post_detach(usb_ia, usba_get_ifno(rdip),
364 364 (struct detachspec *)arg);
365 365 break;
366 366 }
367 367
368 368 break;
369 369 default:
370 370 /* pass to root hub to handle */
371 371 return (usba_bus_ctl(root_hub_dip, rdip, op, arg, result));
372 372 }
373 373
374 374 return (DDI_SUCCESS);
375 375 }
376 376
377 377
378 378 /*
379 379 * bus enumeration entry points
380 380 */
381 381 static int
382 382 usb_ia_bus_config(dev_info_t *dip, uint_t flag, ddi_bus_config_op_t op,
383 383 void *arg, dev_info_t **child)
384 384 {
385 385 int rval, circ;
386 386 usb_ia_t *usb_ia = usb_ia_obtain_state(dip);
387 387
388 388 USB_DPRINTF_L4(DPRINT_MASK_ALL, usb_ia->ia_log_handle,
389 389 "usb_ia_bus_config: op=%d", op);
390 390
391 391 if (usb_ia_bus_config_debug) {
392 392 flag |= NDI_DEVI_DEBUG;
393 393 }
394 394
395 395 ndi_devi_enter(dip, &circ);
396 396
397 397 /* enumerate each interface below us */
398 398 mutex_enter(&usb_ia->ia_mutex);
399 399 usb_ia_create_children(usb_ia);
400 400 mutex_exit(&usb_ia->ia_mutex);
401 401
402 402 rval = ndi_busop_bus_config(dip, flag, op, arg, child, 0);
403 403 ndi_devi_exit(dip, circ);
404 404
405 405 return (rval);
406 406 }
407 407
408 408
409 409 static int
410 410 usb_ia_bus_unconfig(dev_info_t *dip, uint_t flag, ddi_bus_config_op_t op,
411 411 void *arg)
412 412 {
413 413 usb_ia_t *usb_ia = usb_ia_obtain_state(dip);
414 414
415 415 dev_info_t *cdip, *mdip;
416 416 int interface, circular_count;
417 417 int rval = NDI_SUCCESS;
418 418
419 419 USB_DPRINTF_L4(DPRINT_MASK_ALL, usb_ia->ia_log_handle,
420 420 "usb_ia_bus_unconfig: op=%d", op);
421 421
422 422 if (usb_ia_bus_config_debug) {
423 423 flag |= NDI_DEVI_DEBUG;
424 424 }
425 425
426 426 /*
427 427 * first offline and if offlining successful, then
428 428 * remove children
429 429 */
430 430 if (op == BUS_UNCONFIG_ALL) {
431 431 flag &= ~(NDI_DEVI_REMOVE | NDI_UNCONFIG);
432 432 }
433 433
434 434 ndi_devi_enter(dip, &circular_count);
435 435 rval = ndi_busop_bus_unconfig(dip, flag, op, arg);
436 436
437 437 if (op == BUS_UNCONFIG_ALL && rval == NDI_SUCCESS &&
438 438 (flag & NDI_AUTODETACH) == 0) {
439 439 flag |= NDI_DEVI_REMOVE;
440 440 rval = ndi_busop_bus_unconfig(dip, flag, op, arg);
441 441 }
442 442
443 443 /* update children's list */
444 444 mutex_enter(&usb_ia->ia_mutex);
445 445 for (interface = 0; usb_ia->ia_children_dips &&
446 446 (interface < usb_ia->ia_n_ifs); interface++) {
447 447 mdip = usb_ia->ia_children_dips[interface];
448 448
449 449 /* now search if this dip still exists */
450 450 for (cdip = ddi_get_child(dip); cdip && (cdip != mdip); )
451 451 cdip = ddi_get_next_sibling(cdip);
452 452
453 453 if (cdip != mdip) {
454 454 /* we lost the dip on this interface */
455 455 usb_ia->ia_children_dips[interface] = NULL;
456 456 } else if (cdip) {
457 457 /*
458 458 * keep in DS_INITALIZED to prevent parent
459 459 * from detaching
460 460 */
461 461 (void) ddi_initchild(ddi_get_parent(cdip), cdip);
462 462 }
463 463 }
464 464 mutex_exit(&usb_ia->ia_mutex);
465 465
466 466 ndi_devi_exit(dip, circular_count);
467 467
468 468 USB_DPRINTF_L4(DPRINT_MASK_ALL, usb_ia->ia_log_handle,
469 469 "usb_ia_bus_config: rval=%d", rval);
470 470
471 471 return (rval);
472 472 }
473 473
474 474
475 475 /* power entry point */
476 476 /* ARGSUSED */
477 477 static int
478 478 usb_ia_power(dev_info_t *dip, int comp, int level)
479 479 {
480 480 usb_ia_t *usb_ia;
481 481 usb_common_power_t *pm;
482 482 int rval = DDI_FAILURE;
483 483
484 484 usb_ia = usb_ia_obtain_state(dip);
485 485
486 486 USB_DPRINTF_L4(DPRINT_MASK_PM, usb_ia->ia_log_handle,
487 487 "usb_ia_power: Begin: usb_ia = %p, level = %d",
488 488 (void *)usb_ia, level);
489 489
490 490 mutex_enter(&usb_ia->ia_mutex);
491 491 pm = usb_ia->ia_pm;
492 492
493 493 /* check if we are transitioning to a legal power level */
494 494 if (USB_DEV_PWRSTATE_OK(pm->uc_pwr_states, level)) {
495 495 USB_DPRINTF_L2(DPRINT_MASK_PM, usb_ia->ia_log_handle,
496 496 "usb_ia_power: illegal power level = %d "
497 497 "uc_pwr_states = %x", level, pm->uc_pwr_states);
498 498
499 499 mutex_exit(&usb_ia->ia_mutex);
500 500
501 501 return (rval);
502 502 }
503 503
504 504 rval = usba_common_power(dip, &(pm->uc_current_power),
505 505 &(usb_ia->ia_dev_state), level);
506 506
507 507 mutex_exit(&usb_ia->ia_mutex);
508 508
509 509 return (rval);
510 510 }
511 511
512 512 /*
513 513 * attach/resume entry point
514 514 */
515 515 static int
516 516 usb_ia_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
517 517 {
518 518 int instance = ddi_get_instance(dip);
519 519 usb_ia_t *usb_ia = NULL;
520 520 uint_t n_ifs;
521 521 size_t size;
522 522
523 523 switch (cmd) {
524 524 case DDI_ATTACH:
525 525
526 526 break;
527 527 case DDI_RESUME:
528 528 usb_ia = ddi_get_soft_state(usb_ia_statep, instance);
529 529 (void) usb_ia_restore_device_state(dip, usb_ia);
530 530
531 531 return (DDI_SUCCESS);
532 532 default:
533 533
534 534 return (DDI_FAILURE);
535 535 }
536 536
537 537 /*
538 538 * Attach:
539 539 *
540 540 * Allocate soft state and initialize
541 541 */
542 542 if (ddi_soft_state_zalloc(usb_ia_statep, instance) != DDI_SUCCESS) {
543 543 goto fail;
544 544 }
545 545
546 546 usb_ia = ddi_get_soft_state(usb_ia_statep, instance);
547 547 if (usb_ia == NULL) {
548 548
549 549 goto fail;
550 550 }
551 551
552 552 /* allocate handle for logging of messages */
553 553 usb_ia->ia_log_handle = usb_alloc_log_hdl(dip, "ia",
554 554 &usb_ia_errlevel,
555 555 &usb_ia_errmask, &usb_ia_instance_debug,
556 556 0);
557 557
558 558 usb_ia->ia_dip = dip;
559 559 usb_ia->ia_instance = instance;
560 560 usb_ia->ia_first_if = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
561 561 DDI_PROP_DONTPASS, "interface", -1);
562 562 usb_ia->ia_n_ifs = ddi_prop_get_int(DDI_DEV_T_ANY, dip,
563 563 DDI_PROP_DONTPASS, "interface-count", -1);
564 564
565 565 if (usb_ia->ia_first_if < 0 || usb_ia->ia_n_ifs < 0) {
566 566 USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_ia->ia_log_handle,
567 567 "interface-association property failed");
568 568
569 569 goto fail;
570 570 }
571 571
572 572 /* attach client driver to USBA */
573 573 if (usb_client_attach(dip, USBDRV_VERSION, 0) != USB_SUCCESS) {
574 574 USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_ia->ia_log_handle,
575 575 "usb_client_attach failed");
576 576 goto fail;
577 577 }
578 578 if (usb_get_dev_data(dip, &usb_ia->ia_dev_data, USB_PARSE_LVL_NONE,
579 579 0) != USB_SUCCESS) {
580 580 USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_ia->ia_log_handle,
581 581 "usb_get_dev_data failed");
582 582 goto fail;
583 583 }
584 584
585 585 mutex_init(&usb_ia->ia_mutex, NULL, MUTEX_DRIVER,
586 586 usb_ia->ia_dev_data->dev_iblock_cookie);
587 587
588 588 usb_free_dev_data(dip, usb_ia->ia_dev_data);
589 589 usb_ia->ia_dev_data = NULL;
590 590
591 591 usb_ia->ia_init_state |= USB_IA_LOCK_INIT;
592 592
593 593 if (ddi_create_minor_node(dip, "usb_ia", S_IFCHR, instance,
594 594 DDI_NT_NEXUS, 0) != DDI_SUCCESS) {
595 595 USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_ia->ia_log_handle,
596 596 "cannot create devctl minor node");
597 597 goto fail;
598 598 }
599 599
600 600 usb_ia->ia_init_state |= USB_IA_MINOR_NODE_CREATED;
601 601
602 602 /*
603 603 * allocate array for keeping track of child dips
604 604 */
605 605 n_ifs = usb_ia->ia_n_ifs;
606 606 usb_ia->ia_cd_list_length = size = (sizeof (dev_info_t *)) * n_ifs;
607 607
608 608 usb_ia->ia_children_dips = kmem_zalloc(size, KM_SLEEP);
609 609 usb_ia->ia_child_events = kmem_zalloc(sizeof (uint8_t) * n_ifs,
610 610 KM_SLEEP);
611 611 /*
612 612 * Event handling: definition and registration
613 613 * get event handle for events that we have defined
614 614 */
615 615 (void) ndi_event_alloc_hdl(dip, 0, &usb_ia->ia_ndi_event_hdl,
616 616 NDI_SLEEP);
617 617
618 618 /* bind event set to the handle */
619 619 if (ndi_event_bind_set(usb_ia->ia_ndi_event_hdl, &usb_ia_ndi_events,
620 620 NDI_SLEEP)) {
621 621 USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_ia->ia_log_handle,
622 622 "usb_ia_attach: binding event set failed");
623 623
624 624 goto fail;
625 625 }
626 626
627 627 usb_ia->ia_dev_state = USB_DEV_ONLINE;
628 628
629 629 /*
630 630 * now create components to power manage this device
631 631 * before attaching children
632 632 */
633 633 usb_ia_create_pm_components(dip, usb_ia);
634 634
635 635 /* event registration for events from our parent */
636 636 usba_common_register_events(dip, n_ifs, usb_ia_event_cb);
637 637
638 638 usb_ia->ia_init_state |= USB_IA_EVENTS_REGISTERED;
639 639
640 640 ddi_report_dev(dip);
641 641
642 642 return (DDI_SUCCESS);
643 643
644 644 fail:
645 645 USB_DPRINTF_L2(DPRINT_MASK_ATTA, NULL, "usb_ia%d cannot attach",
646 646 instance);
647 647
648 648 if (usb_ia) {
649 649 (void) usb_ia_cleanup(usb_ia);
650 650 }
651 651
652 652 return (DDI_FAILURE);
653 653 }
654 654
655 655
656 656 /* detach or suspend this instance */
657 657 static int
658 658 usb_ia_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
659 659 {
660 660 usb_ia_t *usb_ia = usb_ia_obtain_state(dip);
661 661
662 662 USB_DPRINTF_L4(DPRINT_MASK_ATTA, usb_ia->ia_log_handle,
663 663 "usb_ia_detach: cmd = 0x%x", cmd);
664 664
665 665 switch (cmd) {
666 666 case DDI_DETACH:
667 667
668 668 return (usb_ia_cleanup(usb_ia));
669 669 case DDI_SUSPEND:
670 670 /* nothing to do */
671 671 mutex_enter(&usb_ia->ia_mutex);
672 672 usb_ia->ia_dev_state = USB_DEV_SUSPENDED;
673 673 mutex_exit(&usb_ia->ia_mutex);
674 674
675 675 return (DDI_SUCCESS);
676 676 default:
677 677
678 678 return (DDI_FAILURE);
679 679 }
680 680
681 681 _NOTE(NOT_REACHED)
682 682 /* NOTREACHED */
683 683 }
684 684
685 685
686 686 /*
687 687 * usb_ia_cleanup:
688 688 * cleanup usb_ia and deallocate. this function is called for
689 689 * handling attach failures and detaching including dynamic
690 690 * reconfiguration
691 691 */
692 692 /*ARGSUSED*/
693 693 static int
694 694 usb_ia_cleanup(usb_ia_t *usb_ia)
695 695 {
696 696 usb_common_power_t *iapm;
697 697 int rval;
698 698 dev_info_t *dip = usb_ia->ia_dip;
699 699
700 700 USB_DPRINTF_L4(DPRINT_MASK_ATTA, usb_ia->ia_log_handle,
701 701 "usb_ia_cleanup:");
702 702
703 703 if ((usb_ia->ia_init_state & USB_IA_LOCK_INIT) == 0) {
704 704
705 705 goto done;
706 706 }
707 707
708 708 /*
709 709 * deallocate events, if events are still registered
710 710 * (ie. children still attached) then we have to fail the detach
711 711 */
712 712 if (usb_ia->ia_ndi_event_hdl &&
713 713 (ndi_event_free_hdl(usb_ia->ia_ndi_event_hdl) != NDI_SUCCESS)) {
714 714
715 715 USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_ia->ia_log_handle,
716 716 "usb_ia_cleanup: ndi_event_free_hdl failed");
717 717
718 718 return (DDI_FAILURE);
719 719 }
720 720
721 721 /*
722 722 * Disable the event callbacks, after this point, event
723 723 * callbacks will never get called. Note we shouldn't hold
724 724 * mutex while unregistering events because there may be a
725 725 * competing event callback thread. Event callbacks are done
726 726 * with ndi mutex held and this can cause a potential deadlock.
727 727 * Note that cleanup can't fail after deregistration of events.
728 728 */
729 729 if (usb_ia->ia_init_state & USB_IA_EVENTS_REGISTERED) {
730 730
731 731 usba_common_unregister_events(usb_ia->ia_dip, usb_ia->ia_n_ifs);
732 732 }
733 733
734 734 iapm = usb_ia->ia_pm;
735 735
736 736 mutex_enter(&usb_ia->ia_mutex);
737 737
738 738 if ((iapm) && (usb_ia->ia_dev_state != USB_DEV_DISCONNECTED)) {
739 739
740 740 mutex_exit(&usb_ia->ia_mutex);
741 741
742 742 (void) pm_busy_component(dip, 0);
743 743 if (iapm->uc_wakeup_enabled) {
744 744
745 745 /* First bring the device to full power */
746 746 (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
747 747
748 748 rval = usb_handle_remote_wakeup(dip,
749 749 USB_REMOTE_WAKEUP_DISABLE);
750 750
751 751 if (rval != DDI_SUCCESS) {
752 752 USB_DPRINTF_L2(DPRINT_MASK_EVENTS,
753 753 usb_ia->ia_log_handle,
754 754 "usb_cleanup: disable remote "
755 755 "wakeup failed, rval=%d", rval);
756 756 }
757 757 }
758 758
759 759 (void) pm_lower_power(usb_ia->ia_dip, 0, USB_DEV_OS_PWR_OFF);
760 760 (void) pm_idle_component(dip, 0);
761 761 } else {
762 762 mutex_exit(&usb_ia->ia_mutex);
763 763 }
764 764
765 765 if (iapm) {
766 766 kmem_free(iapm, sizeof (usb_common_power_t));
767 767 }
768 768
769 769 /* free children list */
770 770 if (usb_ia->ia_children_dips) {
771 771 kmem_free(usb_ia->ia_children_dips,
772 772 usb_ia->ia_cd_list_length);
773 773 }
774 774
775 775 if (usb_ia->ia_child_events) {
776 776 kmem_free(usb_ia->ia_child_events, sizeof (uint8_t) *
777 777 usb_ia->ia_n_ifs);
778 778 }
779 779
780 780 if (usb_ia->ia_init_state & USB_IA_MINOR_NODE_CREATED) {
781 781 ddi_remove_minor_node(dip, NULL);
782 782 }
783 783
784 784 mutex_destroy(&usb_ia->ia_mutex);
785 785
786 786 done:
787 787 usb_client_detach(dip, usb_ia->ia_dev_data);
788 788
789 789 usb_free_log_hdl(usb_ia->ia_log_handle);
790 790 ddi_soft_state_free(usb_ia_statep, ddi_get_instance(dip));
791 791
792 792 ddi_prop_remove_all(dip);
793 793
794 794 return (DDI_SUCCESS);
795 795 }
796 796
797 797 /*
798 798 * usb_ia_create_children:
799 799 */
800 800 static void
801 801 usb_ia_create_children(usb_ia_t *usb_ia)
802 802 {
803 803 usba_device_t *usba_device;
804 804 uint_t n_ifs, first_if;
805 805 uint_t i;
806 806 dev_info_t *cdip;
807 807
808 808 usba_device = usba_get_usba_device(usb_ia->ia_dip);
809 809
810 810 USB_DPRINTF_L4(DPRINT_MASK_ATTA, usb_ia->ia_log_handle,
811 811 "usb_ia_attach_child_drivers: port = %d, address = %d",
812 812 usba_device->usb_port, usba_device->usb_addr);
813 813
814 814 n_ifs = usb_ia->ia_n_ifs;
815 815 first_if = usb_ia->ia_first_if;
816 816
817 817 /*
818 818 * create all children if not already present
819 819 */
820 820 for (i = 0; i < n_ifs; i++) {
821 821 if (usb_ia->ia_children_dips[i] != NULL) {
822 822
823 823 continue;
824 824 }
825 825
826 826 mutex_exit(&usb_ia->ia_mutex);
827 827 cdip = usba_ready_interface_node(usb_ia->ia_dip, first_if + i);
828 828 mutex_enter(&usb_ia->ia_mutex);
829 829
830 830 if (cdip != NULL) {
831 831 (void) usba_bind_driver(cdip);
832 832 usb_ia->ia_children_dips[i] = cdip;
833 833 }
834 834 }
835 835
836 836 }
837 837
838 838
839 839 /*
840 840 * event support
841 841 */
842 842 static int
843 843 usb_ia_busop_get_eventcookie(dev_info_t *dip,
844 844 dev_info_t *rdip, char *eventname, ddi_eventcookie_t *cookie)
845 845 {
846 846 usb_ia_t *usb_ia = usb_ia_obtain_state(dip);
847 847
848 848 USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle,
849 849 "usb_ia_busop_get_eventcookie: dip=0x%p, rdip=0x%p, "
850 850 "event=%s", (void *)dip, (void *)rdip, eventname);
851 851 USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle,
852 852 "(dip=%s%d rdip=%s%d)",
853 853 ddi_driver_name(dip), ddi_get_instance(dip),
854 854 ddi_driver_name(rdip), ddi_get_instance(rdip));
855 855
856 856 /* return event cookie, iblock cookie, and level */
857 857 return (ndi_event_retrieve_cookie(usb_ia->ia_ndi_event_hdl,
858 858 rdip, eventname, cookie, NDI_EVENT_NOPASS));
859 859 }
860 860
861 861
862 862 static int
863 863 usb_ia_busop_add_eventcall(dev_info_t *dip,
864 864 dev_info_t *rdip,
865 865 ddi_eventcookie_t cookie,
866 866 void (*callback)(dev_info_t *dip,
867 867 ddi_eventcookie_t cookie, void *arg,
868 868 void *bus_impldata),
869 869 void *arg, ddi_callback_id_t *cb_id)
870 870 {
871 871 int ifno;
872 872 usb_ia_t *usb_ia = usb_ia_obtain_state(dip);
873 873
874 874 mutex_enter(&usb_ia->ia_mutex);
875 875 ifno = usba_get_ifno(rdip)- usb_ia->ia_first_if;
876 876 mutex_exit(&usb_ia->ia_mutex);
877 877
878 878 if (ifno < 0) {
879 879 ifno = 0;
880 880 }
881 881
882 882 USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle,
883 883 "usb_ia_busop_add_eventcall: dip=0x%p, rdip=0x%p "
884 884 "cookie=0x%p, cb=0x%p, arg=0x%p",
885 885 (void *)dip, (void *)rdip, (void *)cookie, (void *)callback, arg);
886 886 USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle,
887 887 "(dip=%s%d rdip=%s%d event=%s)",
888 888 ddi_driver_name(dip), ddi_get_instance(dip),
889 889 ddi_driver_name(rdip), ddi_get_instance(rdip),
890 890 ndi_event_cookie_to_name(usb_ia->ia_ndi_event_hdl, cookie));
891 891
892 892 /* Set flag on children registering events */
893 893 switch (ndi_event_cookie_to_tag(usb_ia->ia_ndi_event_hdl, cookie)) {
894 894 case USBA_EVENT_TAG_HOT_REMOVAL:
895 895 mutex_enter(&usb_ia->ia_mutex);
896 896 usb_ia->ia_child_events[ifno] |=
897 897 USB_IA_CHILD_EVENT_DISCONNECT;
898 898 mutex_exit(&usb_ia->ia_mutex);
899 899
900 900 break;
901 901 case USBA_EVENT_TAG_PRE_SUSPEND:
902 902 mutex_enter(&usb_ia->ia_mutex);
903 903 usb_ia->ia_child_events[ifno] |=
904 904 USB_IA_CHILD_EVENT_PRESUSPEND;
905 905 mutex_exit(&usb_ia->ia_mutex);
906 906
907 907 break;
908 908 default:
909 909
910 910 break;
911 911 }
912 912 /* add callback (perform registration) */
913 913 return (ndi_event_add_callback(usb_ia->ia_ndi_event_hdl,
914 914 rdip, cookie, callback, arg, NDI_SLEEP, cb_id));
915 915 }
916 916
917 917
918 918 static int
919 919 usb_ia_busop_remove_eventcall(dev_info_t *dip, ddi_callback_id_t cb_id)
920 920 {
921 921 usb_ia_t *usb_ia = usb_ia_obtain_state(dip);
922 922 ndi_event_callbacks_t *cb = (ndi_event_callbacks_t *)cb_id;
923 923
924 924 ASSERT(cb);
925 925
926 926 USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle,
927 927 "usb_ia_busop_remove_eventcall: dip=0x%p, rdip=0x%p "
928 928 "cookie=0x%p", (void *)dip, (void *)cb->ndi_evtcb_dip,
929 929 (void *)cb->ndi_evtcb_cookie);
930 930 USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle,
931 931 "(dip=%s%d rdip=%s%d event=%s)",
932 932 ddi_driver_name(dip), ddi_get_instance(dip),
933 933 ddi_driver_name(cb->ndi_evtcb_dip),
934 934 ddi_get_instance(cb->ndi_evtcb_dip),
935 935 ndi_event_cookie_to_name(usb_ia->ia_ndi_event_hdl,
936 936 cb->ndi_evtcb_cookie));
937 937
938 938 /* remove event registration from our event set */
939 939 return (ndi_event_remove_callback(usb_ia->ia_ndi_event_hdl, cb_id));
940 940 }
941 941
942 942
943 943 static int
944 944 usb_ia_busop_post_event(dev_info_t *dip,
945 945 dev_info_t *rdip,
946 946 ddi_eventcookie_t cookie,
947 947 void *bus_impldata)
948 948 {
949 949 usb_ia_t *usb_ia = usb_ia_obtain_state(dip);
950 950
951 951 USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle,
952 952 "usb_ia_busop_post_event: dip=0x%p, rdip=0x%p "
953 953 "cookie=0x%p, impl=0x%p",
954 954 (void *)dip, (void *)rdip, (void *)cookie, bus_impldata);
955 955 USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle,
956 956 "(dip=%s%d rdip=%s%d event=%s)",
957 957 ddi_driver_name(dip), ddi_get_instance(dip),
958 958 ddi_driver_name(rdip), ddi_get_instance(rdip),
959 959 ndi_event_cookie_to_name(usb_ia->ia_ndi_event_hdl, cookie));
960 960
961 961 /* post event to all children registered for this event */
962 962 return (ndi_event_run_callbacks(usb_ia->ia_ndi_event_hdl, rdip,
963 963 cookie, bus_impldata));
964 964 }
965 965
966 966
967 967 /*
968 968 * usb_ia_restore_device_state
969 969 * set the original configuration of the device
970 970 */
971 971 static int
972 972 usb_ia_restore_device_state(dev_info_t *dip, usb_ia_t *usb_ia)
973 973 {
974 974 usb_common_power_t *iapm;
975 975
976 976 USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle,
977 977 "usb_ia_restore_device_state: usb_ia = %p", (void *)usb_ia);
978 978
979 979 mutex_enter(&usb_ia->ia_mutex);
980 980 iapm = usb_ia->ia_pm;
981 981 mutex_exit(&usb_ia->ia_mutex);
982 982
983 983 /* First bring the device to full power */
984 984 (void) pm_busy_component(dip, 0);
985 985 (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
986 986
987 987 if (usb_check_same_device(dip, usb_ia->ia_log_handle, USB_LOG_L0,
988 988 DPRINT_MASK_EVENTS, USB_CHK_VIDPID, NULL) != USB_SUCCESS) {
989 989
990 990 /* change the device state from suspended to disconnected */
991 991 mutex_enter(&usb_ia->ia_mutex);
992 992 usb_ia->ia_dev_state = USB_DEV_DISCONNECTED;
993 993 mutex_exit(&usb_ia->ia_mutex);
994 994 (void) pm_idle_component(dip, 0);
995 995
996 996 return (USB_FAILURE);
997 997 }
998 998
999 999 /*
1000 1000 * if the device had remote wakeup earlier,
1001 1001 * enable it again
1002 1002 */
1003 1003 if (iapm->uc_wakeup_enabled) {
1004 1004 (void) usb_handle_remote_wakeup(usb_ia->ia_dip,
1005 1005 USB_REMOTE_WAKEUP_ENABLE);
1006 1006 }
1007 1007
1008 1008 mutex_enter(&usb_ia->ia_mutex);
1009 1009 usb_ia->ia_dev_state = USB_DEV_ONLINE;
1010 1010 mutex_exit(&usb_ia->ia_mutex);
1011 1011
1012 1012 (void) pm_idle_component(dip, 0);
1013 1013
1014 1014 return (USB_SUCCESS);
1015 1015 }
1016 1016
1017 1017
1018 1018 /*
1019 1019 * usb_ia_event_cb()
1020 1020 * handle disconnect and connect events
1021 1021 */
1022 1022 static void
1023 1023 usb_ia_event_cb(dev_info_t *dip, ddi_eventcookie_t cookie,
1024 1024 void *arg, void *bus_impldata)
1025 1025 {
1026 1026 int i, tag;
1027 1027 usb_ia_t *usb_ia = usb_ia_obtain_state(dip);
1028 1028 dev_info_t *child_dip;
1029 1029 ddi_eventcookie_t rm_cookie, ins_cookie, suspend_cookie, resume_cookie;
1030 1030
1031 1031 USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle,
1032 1032 "usb_ia_event_cb: dip=0x%p, cookie=0x%p, "
1033 1033 "arg=0x%p, impl=0x%p",
1034 1034 (void *)dip, (void *)cookie, arg, bus_impldata);
1035 1035 USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_ia->ia_log_handle,
1036 1036 "(dip=%s%d event=%s)",
1037 1037 ddi_driver_name(dip), ddi_get_instance(dip),
1038 1038 ndi_event_cookie_to_name(usb_ia->ia_ndi_event_hdl, cookie));
1039 1039
1040 1040 tag = NDI_EVENT_TAG(cookie);
1041 1041 rm_cookie = ndi_event_tag_to_cookie(
1042 1042 usb_ia->ia_ndi_event_hdl, USBA_EVENT_TAG_HOT_REMOVAL);
1043 1043 suspend_cookie = ndi_event_tag_to_cookie(
1044 1044 usb_ia->ia_ndi_event_hdl, USBA_EVENT_TAG_PRE_SUSPEND);
1045 1045 ins_cookie = ndi_event_tag_to_cookie(
1046 1046 usb_ia->ia_ndi_event_hdl, USBA_EVENT_TAG_HOT_INSERTION);
1047 1047 resume_cookie = ndi_event_tag_to_cookie(
1048 1048 usb_ia->ia_ndi_event_hdl, USBA_EVENT_TAG_POST_RESUME);
1049 1049
1050 1050 mutex_enter(&usb_ia->ia_mutex);
1051 1051 switch (tag) {
1052 1052 case USBA_EVENT_TAG_HOT_REMOVAL:
1053 1053 if (usb_ia->ia_dev_state == USB_DEV_DISCONNECTED) {
1054 1054 USB_DPRINTF_L2(DPRINT_MASK_EVENTS,
1055 1055 usb_ia->ia_log_handle,
1056 1056 "usb_ia_event_cb: Device already disconnected");
1057 1057 } else {
1058 1058 /* we are disconnected so set our state now */
1059 1059 usb_ia->ia_dev_state = USB_DEV_DISCONNECTED;
1060 1060 for (i = 0; i < usb_ia->ia_n_ifs; i++) {
1061 1061 usb_ia->ia_child_events[i] &= ~
1062 1062 USB_IA_CHILD_EVENT_DISCONNECT;
1063 1063 }
1064 1064 mutex_exit(&usb_ia->ia_mutex);
1065 1065
1066 1066 /* pass disconnect event to all the children */
1067 1067 (void) ndi_event_run_callbacks(
1068 1068 usb_ia->ia_ndi_event_hdl, NULL,
1069 1069 rm_cookie, bus_impldata);
1070 1070
1071 1071 mutex_enter(&usb_ia->ia_mutex);
1072 1072 }
1073 1073 break;
1074 1074 case USBA_EVENT_TAG_PRE_SUSPEND:
1075 1075 /* set our state *after* suspending children */
1076 1076 mutex_exit(&usb_ia->ia_mutex);
1077 1077
1078 1078 /* pass pre_suspend event to all the children */
1079 1079 (void) ndi_event_run_callbacks(usb_ia->ia_ndi_event_hdl,
1080 1080 NULL, suspend_cookie, bus_impldata);
1081 1081
1082 1082 mutex_enter(&usb_ia->ia_mutex);
1083 1083 for (i = 0; i < usb_ia->ia_n_ifs; i++) {
1084 1084 usb_ia->ia_child_events[i] &= ~
1085 1085 USB_IA_CHILD_EVENT_PRESUSPEND;
1086 1086 }
1087 1087 break;
1088 1088 case USBA_EVENT_TAG_HOT_INSERTION:
1089 1089 mutex_exit(&usb_ia->ia_mutex);
1090 1090 if (usb_ia_restore_device_state(dip, usb_ia) == USB_SUCCESS) {
1091 1091
1092 1092 /*
1093 1093 * Check to see if this child has missed the disconnect
1094 1094 * event before it registered for event cb
1095 1095 */
1096 1096 mutex_enter(&usb_ia->ia_mutex);
1097 1097 for (i = 0; i < usb_ia->ia_n_ifs; i++) {
1098 1098 if (usb_ia->ia_child_events[i] &
1099 1099 USB_IA_CHILD_EVENT_DISCONNECT) {
1100 1100 usb_ia->ia_child_events[i] &=
1101 1101 ~USB_IA_CHILD_EVENT_DISCONNECT;
1102 1102 child_dip =
1103 1103 usb_ia->ia_children_dips[i];
1104 1104 mutex_exit(&usb_ia->ia_mutex);
1105 1105
1106 1106 /* post the missed disconnect */
1107 1107 (void) ndi_event_do_callback(
1108 1108 usb_ia->ia_ndi_event_hdl,
1109 1109 child_dip,
1110 1110 rm_cookie,
1111 1111 bus_impldata);
1112 1112 mutex_enter(&usb_ia->ia_mutex);
1113 1113 }
1114 1114 }
1115 1115 mutex_exit(&usb_ia->ia_mutex);
1116 1116
1117 1117 /* pass reconnect event to all the children */
1118 1118 (void) ndi_event_run_callbacks(
1119 1119 usb_ia->ia_ndi_event_hdl, NULL,
1120 1120 ins_cookie, bus_impldata);
1121 1121
1122 1122 }
1123 1123 mutex_enter(&usb_ia->ia_mutex);
1124 1124 break;
1125 1125 case USBA_EVENT_TAG_POST_RESUME:
1126 1126 /*
1127 1127 * Check to see if this child has missed the pre-suspend
1128 1128 * event before it registered for event cb
1129 1129 */
1130 1130 for (i = 0; i < usb_ia->ia_n_ifs; i++) {
1131 1131 if (usb_ia->ia_child_events[i] &
1132 1132 USB_IA_CHILD_EVENT_PRESUSPEND) {
1133 1133 usb_ia->ia_child_events[i] &=
1134 1134 ~USB_IA_CHILD_EVENT_PRESUSPEND;
1135 1135 child_dip = usb_ia->ia_children_dips[i];
1136 1136 mutex_exit(&usb_ia->ia_mutex);
1137 1137
1138 1138 /* post the missed pre-suspend event */
1139 1139 (void) ndi_event_do_callback(
1140 1140 usb_ia->ia_ndi_event_hdl,
1141 1141 child_dip, suspend_cookie,
1142 1142 bus_impldata);
1143 1143 mutex_enter(&usb_ia->ia_mutex);
1144 1144 }
1145 1145 }
1146 1146 mutex_exit(&usb_ia->ia_mutex);
1147 1147
1148 1148 /* pass post_resume event to all the children */
1149 1149 (void) ndi_event_run_callbacks(usb_ia->ia_ndi_event_hdl,
1150 1150 NULL, resume_cookie, bus_impldata);
1151 1151
1152 1152 mutex_enter(&usb_ia->ia_mutex);
1153 1153 break;
1154 1154 }
1155 1155 mutex_exit(&usb_ia->ia_mutex);
1156 1156
1157 1157 }
1158 1158
1159 1159 /*
1160 1160 * create the pm components required for power management
1161 1161 */
1162 1162 static void
1163 1163 usb_ia_create_pm_components(dev_info_t *dip, usb_ia_t *usb_ia)
1164 1164 {
1165 1165 usb_common_power_t *iapm;
1166 1166 uint_t pwr_states;
1167 1167
1168 1168 USB_DPRINTF_L4(DPRINT_MASK_PM, usb_ia->ia_log_handle,
1169 1169 "usb_ia_create_pm_components: Begin");
1170 1170
1171 1171 /* Allocate the PM state structure */
1172 1172 iapm = kmem_zalloc(sizeof (usb_common_power_t), KM_SLEEP);
1173 1173
1174 1174 mutex_enter(&usb_ia->ia_mutex);
1175 1175 usb_ia->ia_pm = iapm;
1176 1176 iapm->uc_usb_statep = usb_ia;
1177 1177 iapm->uc_pm_capabilities = 0; /* XXXX should this be 0?? */
1178 1178 iapm->uc_current_power = USB_DEV_OS_FULL_PWR;
1179 1179 mutex_exit(&usb_ia->ia_mutex);
1180 1180
1181 1181 /*
1182 1182 * By not enabling parental notification, PM enforces
1183 1183 * "strict parental dependency" meaning, usb_ia won't
1184 1184 * power off until any of its children are in full power.
1185 1185 */
1186 1186
1187 1187 /*
1188 1188 * there are 3 scenarios:
1189 1189 * 1. a well behaved device should have remote wakeup
1190 1190 * at interface and device level. If the interface
1191 1191 * wakes up, usb_ia will wake up
1192 1192 * 2. if the device doesn't have remote wake up and
1193 1193 * the interface has, PM will still work, ie.
1194 1194 * the interfaces wakes up and usb_ia wakes up
1195 1195 * 3. if neither the interface nor device has remote
1196 1196 * wakeup, the interface will wake up when it is opened
1197 1197 * and goes to sleep after being closed for a while
1198 1198 * In this case usb_ia should also go to sleep shortly
1199 1199 * thereafter
1200 1200 * In all scenarios it doesn't really matter whether
1201 1201 * remote wakeup at the device level is enabled or not
1202 1202 * but we do it anyways
1203 1203 */
1204 1204 if (usb_handle_remote_wakeup(dip, USB_REMOTE_WAKEUP_ENABLE) ==
1205 1205 USB_SUCCESS) {
1206 1206 USB_DPRINTF_L3(DPRINT_MASK_PM, usb_ia->ia_log_handle,
1207 1207 "usb_ia_create_pm_components: "
1208 1208 "Remote Wakeup Enabled");
1209 1209 iapm->uc_wakeup_enabled = 1;
1210 1210 }
1211 1211
1212 1212 if (usb_create_pm_components(dip, &pwr_states) ==
1213 1213 USB_SUCCESS) {
1214 1214 iapm->uc_pwr_states = (uint8_t)pwr_states;
1215 1215 (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
1216 1216 }
1217 1217
1218 1218 USB_DPRINTF_L4(DPRINT_MASK_PM, usb_ia->ia_log_handle,
1219 1219 "usb_ia_create_pm_components: End");
1220 1220 }
1221 1221
1222 1222
1223 1223 /*
1224 1224 * usb_ia_obtain_state:
1225 1225 */
1226 1226 static usb_ia_t *
1227 1227 usb_ia_obtain_state(dev_info_t *dip)
1228 1228 {
1229 1229 int instance = ddi_get_instance(dip);
1230 1230 usb_ia_t *statep = ddi_get_soft_state(usb_ia_statep, instance);
1231 1231
1232 1232 ASSERT(statep != NULL);
1233 1233
1234 1234 return (statep);
1235 1235 }
↓ open down ↓ |
1042 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX