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_mid/usb_mid.c
+++ new/usr/src/uts/common/io/usb/usb_mid/usb_mid.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 2008 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 multi interface and common class driver
32 32 *
33 33 * this driver attempts to attach each interface to a driver
34 34 * and may eventually handle common class features such as
35 35 * shared endpoints
36 36 */
37 37
38 38 #if defined(lint) && !defined(DEBUG)
39 39 #define DEBUG 1
40 40 #endif
41 41 #include <sys/usb/usba/usbai_version.h>
42 42 #include <sys/usb/usba.h>
43 43 #include <sys/usb/usba/usba_types.h>
44 44 #include <sys/usb/usba/usba_impl.h>
45 45 #include <sys/usb/usba/usba_ugen.h>
46 46 #include <sys/usb/usb_mid/usb_midvar.h>
47 47
48 48 void usba_free_evdata(usba_evdata_t *);
49 49
50 50 /* Debugging support */
51 51 uint_t usb_mid_errlevel = USB_LOG_L4;
52 52 uint_t usb_mid_errmask = (uint_t)DPRINT_MASK_ALL;
53 53 uint_t usb_mid_instance_debug = (uint_t)-1;
54 54 uint_t usb_mid_bus_config_debug = 0;
55 55
56 56 _NOTE(DATA_READABLE_WITHOUT_LOCK(usb_mid_errlevel))
57 57 _NOTE(DATA_READABLE_WITHOUT_LOCK(usb_mid_errmask))
58 58 _NOTE(DATA_READABLE_WITHOUT_LOCK(usb_mid_instance_debug))
59 59
60 60 _NOTE(SCHEME_PROTECTS_DATA("unique", msgb))
61 61 _NOTE(SCHEME_PROTECTS_DATA("unique", dev_info))
62 62 _NOTE(SCHEME_PROTECTS_DATA("unique", usb_pipe_policy))
63 63
64 64 /*
65 65 * Hotplug support
66 66 * Leaf ops (hotplug controls for client devices)
67 67 */
68 68 static int usb_mid_open(dev_t *, int, int, cred_t *);
69 69 static int usb_mid_close(dev_t, int, int, cred_t *);
70 70 static int usb_mid_read(dev_t, struct uio *, cred_t *);
71 71 static int usb_mid_write(dev_t, struct uio *, cred_t *);
72 72 static int usb_mid_poll(dev_t, short, int, short *,
73 73 struct pollhead **);
74 74
75 75 static struct cb_ops usb_mid_cb_ops = {
76 76 usb_mid_open,
77 77 usb_mid_close,
78 78 nodev, /* strategy */
79 79 nodev, /* print */
80 80 nodev, /* dump */
81 81 usb_mid_read, /* read */
82 82 usb_mid_write, /* write */
83 83 nodev,
84 84 nodev, /* devmap */
85 85 nodev, /* mmap */
86 86 nodev, /* segmap */
87 87 usb_mid_poll, /* poll */
88 88 ddi_prop_op, /* prop_op */
89 89 NULL,
90 90 D_MP
91 91 };
92 92
93 93 static int usb_mid_busop_get_eventcookie(dev_info_t *dip,
94 94 dev_info_t *rdip,
95 95 char *eventname,
96 96 ddi_eventcookie_t *cookie);
97 97 static int usb_mid_busop_add_eventcall(dev_info_t *dip,
98 98 dev_info_t *rdip,
99 99 ddi_eventcookie_t cookie,
100 100 void (*callback)(dev_info_t *dip,
101 101 ddi_eventcookie_t cookie, void *arg,
102 102 void *bus_impldata),
103 103 void *arg, ddi_callback_id_t *cb_id);
104 104 static int usb_mid_busop_remove_eventcall(dev_info_t *dip,
105 105 ddi_callback_id_t cb_id);
106 106 static int usb_mid_busop_post_event(dev_info_t *dip,
107 107 dev_info_t *rdip,
108 108 ddi_eventcookie_t cookie,
109 109 void *bus_impldata);
110 110 static int usb_mid_bus_config(dev_info_t *dip,
111 111 uint_t flag,
112 112 ddi_bus_config_op_t op,
113 113 void *arg,
114 114 dev_info_t **child);
115 115 static int usb_mid_bus_unconfig(dev_info_t *dip,
116 116 uint_t flag,
117 117 ddi_bus_config_op_t op,
118 118 void *arg);
119 119
120 120
121 121 /*
122 122 * autoconfiguration data and routines.
123 123 */
124 124 static int usb_mid_info(dev_info_t *, ddi_info_cmd_t,
125 125 void *, void **);
126 126 static int usb_mid_attach(dev_info_t *, ddi_attach_cmd_t);
127 127 static int usb_mid_detach(dev_info_t *, ddi_detach_cmd_t);
128 128
129 129 /* other routines */
130 130 static void usb_mid_create_pm_components(dev_info_t *, usb_mid_t *);
131 131 static int usb_mid_bus_ctl(dev_info_t *, dev_info_t *,
132 132 ddi_ctl_enum_t, void *, void *);
133 133 static int usb_mid_power(dev_info_t *, int, int);
134 134 static int usb_mid_restore_device_state(dev_info_t *, usb_mid_t *);
135 135 static usb_mid_t *usb_mid_obtain_state(dev_info_t *);
136 136 static void usb_mid_event_cb(dev_info_t *, ddi_eventcookie_t, void *, void *);
137 137
138 138 /*
139 139 * Busops vector
140 140 */
141 141 static struct bus_ops usb_mid_busops = {
142 142 BUSO_REV,
143 143 nullbusmap, /* bus_map */
144 144 NULL, /* bus_get_intrspec */
145 145 NULL, /* bus_add_intrspec */
146 146 NULL, /* bus_remove_intrspec */
147 147 NULL, /* XXXX bus_map_fault */
148 148 NULL, /* bus_dma_map */
149 149 ddi_dma_allochdl,
150 150 ddi_dma_freehdl,
151 151 ddi_dma_bindhdl,
152 152 ddi_dma_unbindhdl,
153 153 ddi_dma_flush,
154 154 ddi_dma_win,
155 155 ddi_dma_mctl, /* bus_dma_ctl */
156 156 usb_mid_bus_ctl, /* bus_ctl */
157 157 ddi_bus_prop_op, /* bus_prop_op */
158 158 usb_mid_busop_get_eventcookie,
159 159 usb_mid_busop_add_eventcall,
160 160 usb_mid_busop_remove_eventcall,
161 161 usb_mid_busop_post_event, /* bus_post_event */
162 162 NULL, /* bus_intr_ctl */
163 163 usb_mid_bus_config, /* bus_config */
164 164 usb_mid_bus_unconfig, /* bus_unconfig */
165 165 NULL, /* bus_fm_init */
166 166 NULL, /* bus_fm_fini */
167 167 NULL, /* bus_fm_access_enter */
168 168 NULL, /* bus_fm_access_exit */
169 169 NULL /* bus_power */
170 170 };
171 171
172 172
173 173 static struct dev_ops usb_mid_ops = {
174 174 DEVO_REV, /* devo_rev, */
175 175 0, /* refcnt */
176 176 usb_mid_info, /* info */
177 177 nulldev, /* identify */
178 178 nulldev, /* probe */
179 179 usb_mid_attach, /* attach */
180 180 usb_mid_detach, /* detach */
181 181 nodev, /* reset */
182 182 &usb_mid_cb_ops, /* driver operations */
183 183 &usb_mid_busops, /* bus operations */
184 184 usb_mid_power, /* power */
↓ open down ↓ |
184 lines elided |
↑ open up ↑ |
185 185 ddi_quiesce_not_needed, /* quiesce */
186 186 };
187 187
188 188 static struct modldrv modldrv = {
189 189 &mod_driverops, /* Type of module. This one is a driver */
190 190 "USB Multi Interface Driver", /* Name of the module. */
191 191 &usb_mid_ops, /* driver ops */
192 192 };
193 193
194 194 static struct modlinkage modlinkage = {
195 - MODREV_1, (void *)&modldrv, NULL
195 + MODREV_1, { (void *)&modldrv, NULL }
196 196 };
197 197
198 198 #define USB_MID_INITIAL_SOFT_SPACE 4
199 199 static void *usb_mid_statep;
200 200
201 201
202 202 /*
203 203 * prototypes
204 204 */
205 205 static void usb_mid_create_children(usb_mid_t *usb_mid);
206 206 static int usb_mid_cleanup(dev_info_t *dip, usb_mid_t *usb_mid);
207 207
208 208 /*
209 209 * event definition
210 210 */
211 211 static ndi_event_definition_t usb_mid_ndi_event_defs[] = {
212 212 {USBA_EVENT_TAG_HOT_REMOVAL, DDI_DEVI_REMOVE_EVENT, EPL_KERNEL,
213 213 NDI_EVENT_POST_TO_ALL},
214 214 {USBA_EVENT_TAG_HOT_INSERTION, DDI_DEVI_INSERT_EVENT, EPL_KERNEL,
215 215 NDI_EVENT_POST_TO_ALL},
216 216 {USBA_EVENT_TAG_POST_RESUME, USBA_POST_RESUME_EVENT, EPL_KERNEL,
217 217 NDI_EVENT_POST_TO_ALL},
218 218 {USBA_EVENT_TAG_PRE_SUSPEND, USBA_PRE_SUSPEND_EVENT, EPL_KERNEL,
219 219 NDI_EVENT_POST_TO_ALL}
220 220 };
221 221
222 222 #define USB_MID_N_NDI_EVENTS \
223 223 (sizeof (usb_mid_ndi_event_defs) / sizeof (ndi_event_definition_t))
224 224
225 225 static ndi_event_set_t usb_mid_ndi_events = {
226 226 NDI_EVENTS_REV1, USB_MID_N_NDI_EVENTS, usb_mid_ndi_event_defs};
227 227
228 228
229 229 /*
230 230 * standard driver entry points
231 231 */
232 232 int
233 233 _init(void)
234 234 {
235 235 int rval;
236 236
237 237 rval = ddi_soft_state_init(&usb_mid_statep, sizeof (struct usb_mid),
238 238 USB_MID_INITIAL_SOFT_SPACE);
239 239 if (rval != 0) {
240 240 return (rval);
241 241 }
242 242
243 243 if ((rval = mod_install(&modlinkage)) != 0) {
244 244 ddi_soft_state_fini(&usb_mid_statep);
245 245 return (rval);
246 246 }
247 247
248 248 return (rval);
249 249 }
250 250
251 251
252 252 int
253 253 _fini(void)
254 254 {
255 255 int rval;
256 256
257 257 rval = mod_remove(&modlinkage);
258 258
259 259 if (rval) {
260 260 return (rval);
261 261 }
262 262
263 263 ddi_soft_state_fini(&usb_mid_statep);
264 264
265 265 return (rval);
266 266 }
267 267
268 268
269 269 int
270 270 _info(struct modinfo *modinfop)
271 271 {
272 272 return (mod_info(&modlinkage, modinfop));
273 273 }
274 274
275 275
276 276 /*ARGSUSED*/
277 277 static int
278 278 usb_mid_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
279 279 {
280 280 usb_mid_t *usb_mid;
281 281 int instance =
282 282 USB_MID_MINOR_TO_INSTANCE(getminor((dev_t)arg));
283 283 int error = DDI_FAILURE;
284 284
285 285 switch (infocmd) {
286 286 case DDI_INFO_DEVT2DEVINFO:
287 287 if ((usb_mid = ddi_get_soft_state(usb_mid_statep,
288 288 instance)) != NULL) {
289 289 *result = (void *)usb_mid->mi_dip;
290 290 if (*result != NULL) {
291 291 error = DDI_SUCCESS;
292 292 }
293 293 } else {
294 294 *result = NULL;
295 295 }
296 296 break;
297 297
298 298 case DDI_INFO_DEVT2INSTANCE:
299 299 *result = (void *)(intptr_t)instance;
300 300 error = DDI_SUCCESS;
301 301 break;
302 302 default:
303 303 break;
304 304 }
305 305
306 306 return (error);
307 307 }
308 308
309 309
310 310 /*
311 311 * child post attach/detach notification
312 312 */
313 313 static void
314 314 usb_mid_post_attach(usb_mid_t *usb_mid, uint8_t ifno, struct attachspec *as)
315 315 {
316 316 USB_DPRINTF_L2(DPRINT_MASK_PM, usb_mid->mi_log_handle,
317 317 "usb_mid_post_attach: ifno = %d result = %d", ifno, as->result);
318 318
319 319 /* if child successfully attached, set power */
320 320 if (as->result == DDI_SUCCESS) {
321 321 /*
322 322 * Check if the child created wants to be power managed.
323 323 * If yes, the childs power level gets automatically tracked
324 324 * by DDI_CTLOPS_POWER busctl.
325 325 * If no, we set power of the new child by default
326 326 * to USB_DEV_OS_FULL_PWR. Because we should never suspend.
327 327 */
328 328 mutex_enter(&usb_mid->mi_mutex);
329 329 usb_mid->mi_attach_count++;
330 330 mutex_exit(&usb_mid->mi_mutex);
331 331 }
332 332 }
333 333
334 334
335 335 static void
336 336 usb_mid_post_detach(usb_mid_t *usb_mid, uint8_t ifno, struct detachspec *ds)
337 337 {
338 338 USB_DPRINTF_L2(DPRINT_MASK_PM, usb_mid->mi_log_handle,
339 339 "usb_mid_post_detach: ifno = %d result = %d", ifno, ds->result);
340 340
341 341 /*
342 342 * if the device is successfully detached,
343 343 * mark component as idle
344 344 */
345 345 if (ds->result == DDI_SUCCESS) {
346 346 usba_device_t *usba_device =
347 347 usba_get_usba_device(usb_mid->mi_dip);
348 348
349 349 mutex_enter(&usb_mid->mi_mutex);
350 350
351 351 /* check for leaks except when where is a ugen open */
352 352 if ((ds->cmd == DDI_DETACH) &&
353 353 (--usb_mid->mi_attach_count == 0) && usba_device &&
354 354 (usb_mid->mi_ugen_open_count == 0)) {
355 355 usba_check_for_leaks(usba_device);
356 356 }
357 357 mutex_exit(&usb_mid->mi_mutex);
358 358 }
359 359 }
360 360
361 361
362 362 /*
363 363 * bus ctl support. we handle notifications here and the
364 364 * rest goes up to root hub/hcd
365 365 */
366 366 /*ARGSUSED*/
367 367 static int
368 368 usb_mid_bus_ctl(dev_info_t *dip,
369 369 dev_info_t *rdip,
370 370 ddi_ctl_enum_t op,
371 371 void *arg,
372 372 void *result)
373 373 {
374 374 usba_device_t *hub_usba_device = usba_get_usba_device(rdip);
375 375 dev_info_t *root_hub_dip = hub_usba_device->usb_root_hub_dip;
376 376 usb_mid_t *usb_mid;
377 377 struct attachspec *as;
378 378 struct detachspec *ds;
379 379
380 380 usb_mid = usb_mid_obtain_state(dip);
381 381
382 382 USB_DPRINTF_L2(DPRINT_MASK_PM, usb_mid->mi_log_handle,
383 383 "usb_mid_bus_ctl:\n\t"
384 384 "dip = 0x%p, rdip = 0x%p, op = 0x%x, arg = 0x%p",
385 385 (void *)dip, (void *)rdip, op, arg);
386 386
387 387 switch (op) {
388 388 case DDI_CTLOPS_ATTACH:
389 389 as = (struct attachspec *)arg;
390 390
391 391 switch (as->when) {
392 392 case DDI_PRE :
393 393 /* nothing to do basically */
394 394 USB_DPRINTF_L2(DPRINT_MASK_PM, usb_mid->mi_log_handle,
395 395 "DDI_PRE DDI_CTLOPS_ATTACH");
396 396 break;
397 397 case DDI_POST :
398 398 usb_mid_post_attach(usb_mid, usba_get_ifno(rdip),
399 399 (struct attachspec *)arg);
400 400 break;
401 401 }
402 402
403 403 break;
404 404 case DDI_CTLOPS_DETACH:
405 405 ds = (struct detachspec *)arg;
406 406
407 407 switch (ds->when) {
408 408 case DDI_PRE :
409 409 /* nothing to do basically */
410 410 USB_DPRINTF_L2(DPRINT_MASK_PM, usb_mid->mi_log_handle,
411 411 "DDI_PRE DDI_CTLOPS_DETACH");
412 412 break;
413 413 case DDI_POST :
414 414 usb_mid_post_detach(usb_mid, usba_get_ifno(rdip),
415 415 (struct detachspec *)arg);
416 416 break;
417 417 }
418 418
419 419 break;
420 420 default:
421 421 /* pass to root hub to handle */
422 422 return (usba_bus_ctl(root_hub_dip, rdip, op, arg, result));
423 423 }
424 424
425 425 return (DDI_SUCCESS);
426 426 }
427 427
428 428
429 429 /*
430 430 * bus enumeration entry points
431 431 */
432 432 static int
433 433 usb_mid_bus_config(dev_info_t *dip, uint_t flag, ddi_bus_config_op_t op,
434 434 void *arg, dev_info_t **child)
435 435 {
436 436 int rval, circ;
437 437 usb_mid_t *usb_mid = usb_mid_obtain_state(dip);
438 438
439 439 USB_DPRINTF_L2(DPRINT_MASK_ALL, usb_mid->mi_log_handle,
440 440 "usb_mid_bus_config: op=%d", op);
441 441
442 442 if (usb_mid_bus_config_debug) {
443 443 flag |= NDI_DEVI_DEBUG;
444 444 }
445 445
446 446 ndi_devi_enter(dip, &circ);
447 447
448 448 /* enumerate each interface below us */
449 449 mutex_enter(&usb_mid->mi_mutex);
450 450 usb_mid_create_children(usb_mid);
451 451 mutex_exit(&usb_mid->mi_mutex);
452 452
453 453 rval = ndi_busop_bus_config(dip, flag, op, arg, child, 0);
454 454 ndi_devi_exit(dip, circ);
455 455
456 456 return (rval);
457 457 }
458 458
459 459
460 460 static int
461 461 usb_mid_bus_unconfig(dev_info_t *dip, uint_t flag, ddi_bus_config_op_t op,
462 462 void *arg)
463 463 {
464 464 usb_mid_t *usb_mid = usb_mid_obtain_state(dip);
465 465
466 466 dev_info_t *cdip, *mdip;
467 467 int interface, circular_count;
468 468 int rval = NDI_SUCCESS;
469 469
470 470 USB_DPRINTF_L4(DPRINT_MASK_ALL, usb_mid->mi_log_handle,
471 471 "usb_mid_bus_unconfig: op=%d", op);
472 472
473 473 if (usb_mid_bus_config_debug) {
474 474 flag |= NDI_DEVI_DEBUG;
475 475 }
476 476
477 477 /*
478 478 * first offline and if offlining successful, then
479 479 * remove children
480 480 */
481 481 if (op == BUS_UNCONFIG_ALL) {
482 482 flag &= ~(NDI_DEVI_REMOVE | NDI_UNCONFIG);
483 483 }
484 484
485 485 ndi_devi_enter(dip, &circular_count);
486 486 rval = ndi_busop_bus_unconfig(dip, flag, op, arg);
487 487
488 488 if (op == BUS_UNCONFIG_ALL && rval == NDI_SUCCESS &&
489 489 (flag & NDI_AUTODETACH) == 0) {
490 490 flag |= NDI_DEVI_REMOVE;
491 491 rval = ndi_busop_bus_unconfig(dip, flag, op, arg);
492 492 }
493 493
494 494 /* update children's list */
495 495 mutex_enter(&usb_mid->mi_mutex);
496 496 for (interface = 0; usb_mid->mi_children_dips &&
497 497 (interface < usb_mid->mi_n_ifs) &&
498 498 (usb_mid->mi_children_ifs[interface]); interface++) {
499 499 mdip = usb_mid->mi_children_dips[interface];
500 500
501 501 /* now search if this dip still exists */
502 502 for (cdip = ddi_get_child(dip); cdip && (cdip != mdip); )
503 503 cdip = ddi_get_next_sibling(cdip);
504 504
505 505 if (cdip != mdip) {
506 506 /* we lost the dip on this interface */
507 507 usb_mid->mi_children_dips[interface] = NULL;
508 508 } else if (cdip) {
509 509 /*
510 510 * keep in DS_INITALIZED to prevent parent
511 511 * from detaching
512 512 */
513 513 (void) ddi_initchild(ddi_get_parent(cdip), cdip);
514 514 }
515 515 }
516 516 mutex_exit(&usb_mid->mi_mutex);
517 517
518 518 ndi_devi_exit(dip, circular_count);
519 519
520 520 USB_DPRINTF_L4(DPRINT_MASK_ALL, usb_mid->mi_log_handle,
521 521 "usb_mid_bus_config: rval=%d", rval);
522 522
523 523 return (rval);
524 524 }
525 525
526 526
527 527 /* power entry point */
528 528 /* ARGSUSED */
529 529 static int
530 530 usb_mid_power(dev_info_t *dip, int comp, int level)
531 531 {
532 532 usb_mid_t *usb_mid;
533 533 usb_common_power_t *midpm;
534 534 int rval = DDI_FAILURE;
535 535
536 536 usb_mid = usb_mid_obtain_state(dip);
537 537
538 538 USB_DPRINTF_L4(DPRINT_MASK_PM, usb_mid->mi_log_handle,
539 539 "usb_mid_power: Begin: usb_mid = %p, level = %d",
540 540 (void *)usb_mid, level);
541 541
542 542 mutex_enter(&usb_mid->mi_mutex);
543 543 midpm = usb_mid->mi_pm;
544 544
545 545 /* check if we are transitioning to a legal power level */
546 546 if (USB_DEV_PWRSTATE_OK(midpm->uc_pwr_states, level)) {
547 547 USB_DPRINTF_L2(DPRINT_MASK_PM, usb_mid->mi_log_handle,
548 548 "usb_mid_power: illegal power level = %d "
549 549 "uc_pwr_states = %x", level, midpm->uc_pwr_states);
550 550
551 551 mutex_exit(&usb_mid->mi_mutex);
552 552
553 553 return (rval);
554 554 }
555 555
556 556 rval = usba_common_power(dip, &(midpm->uc_current_power),
557 557 &(usb_mid->mi_dev_state), level);
558 558
559 559 mutex_exit(&usb_mid->mi_mutex);
560 560
561 561 return (rval);
562 562 }
563 563
564 564
565 565 /*
566 566 * attach/resume entry point
567 567 */
568 568 static int
569 569 usb_mid_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
570 570 {
571 571 int instance = ddi_get_instance(dip);
572 572 usb_mid_t *usb_mid = NULL;
573 573 uint_t n_ifs, i;
574 574 size_t size;
575 575
576 576 switch (cmd) {
577 577 case DDI_ATTACH:
578 578
579 579 break;
580 580 case DDI_RESUME:
581 581 usb_mid = (usb_mid_t *)ddi_get_soft_state(usb_mid_statep,
582 582 instance);
583 583 (void) usb_mid_restore_device_state(dip, usb_mid);
584 584
585 585 if (usb_mid->mi_ugen_hdl) {
586 586 (void) usb_ugen_attach(usb_mid->mi_ugen_hdl,
587 587 DDI_RESUME);
588 588 }
589 589
590 590 return (DDI_SUCCESS);
591 591 default:
592 592
593 593 return (DDI_FAILURE);
594 594 }
595 595
596 596 /*
597 597 * Attach:
598 598 *
599 599 * Allocate soft state and initialize
600 600 */
601 601 if (ddi_soft_state_zalloc(usb_mid_statep, instance) != DDI_SUCCESS) {
602 602 goto fail;
603 603 }
604 604
605 605 usb_mid = ddi_get_soft_state(usb_mid_statep, instance);
606 606 if (usb_mid == NULL) {
607 607
608 608 goto fail;
609 609 }
610 610
611 611 /* allocate handle for logging of messages */
612 612 usb_mid->mi_log_handle = usb_alloc_log_hdl(dip, "mid",
613 613 &usb_mid_errlevel,
614 614 &usb_mid_errmask, &usb_mid_instance_debug,
615 615 0);
616 616
617 617 usb_mid->mi_usba_device = usba_get_usba_device(dip);
618 618 usb_mid->mi_dip = dip;
619 619 usb_mid->mi_instance = instance;
620 620 usb_mid->mi_n_ifs = usb_mid->mi_usba_device->usb_n_ifs;
621 621
622 622 /* attach client driver to USBA */
623 623 if (usb_client_attach(dip, USBDRV_VERSION, 0) != USB_SUCCESS) {
624 624 USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_mid->mi_log_handle,
625 625 "usb_client_attach failed");
626 626 goto fail;
627 627 }
628 628 if (usb_get_dev_data(dip, &usb_mid->mi_dev_data, USB_PARSE_LVL_NONE,
629 629 0) != USB_SUCCESS) {
630 630 USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_mid->mi_log_handle,
631 631 "usb_get_dev_data failed");
632 632 goto fail;
633 633 }
634 634
635 635 mutex_init(&usb_mid->mi_mutex, NULL, MUTEX_DRIVER,
636 636 usb_mid->mi_dev_data->dev_iblock_cookie);
637 637
638 638 usb_free_dev_data(dip, usb_mid->mi_dev_data);
639 639 usb_mid->mi_dev_data = NULL;
640 640
641 641 usb_mid->mi_init_state |= USB_MID_LOCK_INIT;
642 642
643 643 if (ddi_create_minor_node(dip, "usb_mid", S_IFCHR,
644 644 instance << USB_MID_MINOR_INSTANCE_SHIFT,
645 645 DDI_NT_NEXUS, 0) != DDI_SUCCESS) {
646 646 USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_mid->mi_log_handle,
647 647 "cannot create devctl minor node");
648 648 goto fail;
649 649 }
650 650
651 651 usb_mid->mi_init_state |= USB_MID_MINOR_NODE_CREATED;
652 652
653 653 /*
654 654 * allocate array for keeping track of child dips
655 655 */
656 656 n_ifs = usb_mid->mi_n_ifs;
657 657 usb_mid->mi_cd_list_length = size = (sizeof (dev_info_t *)) * n_ifs;
658 658
659 659 usb_mid->mi_children_dips = kmem_zalloc(size, KM_SLEEP);
660 660 usb_mid->mi_child_events = kmem_zalloc(sizeof (uint8_t) * n_ifs,
661 661 KM_SLEEP);
662 662 usb_mid->mi_children_ifs = kmem_zalloc(sizeof (uint_t) * n_ifs,
663 663 KM_SLEEP);
664 664 for (i = 0; i < n_ifs; i++) {
665 665 usb_mid->mi_children_ifs[i] = 1;
666 666 }
667 667
668 668 /*
669 669 * Event handling: definition and registration
670 670 * get event handle for events that we have defined
671 671 */
672 672 (void) ndi_event_alloc_hdl(dip, 0, &usb_mid->mi_ndi_event_hdl,
673 673 NDI_SLEEP);
674 674
675 675 /* bind event set to the handle */
676 676 if (ndi_event_bind_set(usb_mid->mi_ndi_event_hdl, &usb_mid_ndi_events,
677 677 NDI_SLEEP)) {
678 678 USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_mid->mi_log_handle,
679 679 "usb_mid_attach: binding event set failed");
680 680
681 681 goto fail;
682 682 }
683 683
684 684 usb_mid->mi_dev_state = USB_DEV_ONLINE;
685 685
686 686 /*
687 687 * now create components to power manage this device
688 688 * before attaching children
689 689 */
690 690 usb_mid_create_pm_components(dip, usb_mid);
691 691
692 692 /* event registration for events from our parent */
693 693 usba_common_register_events(usb_mid->mi_dip, 1, usb_mid_event_cb);
694 694
695 695 usb_mid->mi_init_state |= USB_MID_EVENTS_REGISTERED;
696 696
697 697 ddi_report_dev(dip);
698 698
699 699 return (DDI_SUCCESS);
700 700
701 701 fail:
702 702 USB_DPRINTF_L2(DPRINT_MASK_ATTA, NULL, "usb_mid%d cannot attach",
703 703 instance);
704 704
705 705 if (usb_mid) {
706 706 (void) usb_mid_cleanup(dip, usb_mid);
707 707 }
708 708
709 709 return (DDI_FAILURE);
710 710 }
711 711
712 712
713 713 /* detach or suspend this instance */
714 714 static int
715 715 usb_mid_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
716 716 {
717 717 usb_mid_t *usb_mid = usb_mid_obtain_state(dip);
718 718
719 719 USB_DPRINTF_L4(DPRINT_MASK_ATTA, usb_mid->mi_log_handle,
720 720 "usb_mid_detach: cmd = 0x%x", cmd);
721 721
722 722 switch (cmd) {
723 723 case DDI_DETACH:
724 724
725 725 return (usb_mid_cleanup(dip, usb_mid));
726 726 case DDI_SUSPEND:
727 727 /* nothing to do */
728 728 mutex_enter(&usb_mid->mi_mutex);
729 729 usb_mid->mi_dev_state = USB_DEV_SUSPENDED;
730 730 mutex_exit(&usb_mid->mi_mutex);
731 731
732 732 if (usb_mid->mi_ugen_hdl) {
733 733 int rval = usb_ugen_detach(usb_mid->mi_ugen_hdl,
734 734 DDI_SUSPEND);
735 735 return (rval == USB_SUCCESS ? DDI_SUCCESS :
736 736 DDI_FAILURE);
737 737 }
738 738
739 739 return (DDI_SUCCESS);
740 740 default:
741 741
742 742 return (DDI_FAILURE);
743 743 }
744 744
745 745 _NOTE(NOT_REACHED)
746 746 /* NOTREACHED */
747 747 }
748 748
749 749 /*
750 750 * usb_mid_cleanup:
751 751 * cleanup usb_mid and deallocate. this function is called for
752 752 * handling attach failures and detaching including dynamic
753 753 * reconfiguration
754 754 */
755 755 /*ARGSUSED*/
756 756 static int
757 757 usb_mid_cleanup(dev_info_t *dip, usb_mid_t *usb_mid)
758 758 {
759 759 usb_common_power_t *midpm;
760 760 int rval;
761 761
762 762 USB_DPRINTF_L4(DPRINT_MASK_ATTA, usb_mid->mi_log_handle,
763 763 "usb_mid_cleanup:");
764 764
765 765 if ((usb_mid->mi_init_state & USB_MID_LOCK_INIT) == 0) {
766 766
767 767 goto done;
768 768 }
769 769
770 770 /*
771 771 * deallocate events, if events are still registered
772 772 * (ie. children still attached) then we have to fail the detach
773 773 */
774 774 if (usb_mid->mi_ndi_event_hdl &&
775 775 (ndi_event_free_hdl(usb_mid->mi_ndi_event_hdl) != NDI_SUCCESS)) {
776 776
777 777 USB_DPRINTF_L2(DPRINT_MASK_ATTA, usb_mid->mi_log_handle,
778 778 "usb_mid_cleanup: ndi_event_free_hdl failed");
779 779
780 780 return (DDI_FAILURE);
781 781 }
782 782
783 783 /*
784 784 * Disable the event callbacks, after this point, event
785 785 * callbacks will never get called. Note we shouldn't hold
786 786 * mutex while unregistering events because there may be a
787 787 * competing event callback thread. Event callbacks are done
788 788 * with ndi mutex held and this can cause a potential deadlock.
789 789 * Note that cleanup can't fail after deregistration of events.
790 790 */
791 791 if (usb_mid->mi_init_state & USB_MID_EVENTS_REGISTERED) {
792 792 usba_common_unregister_events(usb_mid->mi_dip, 1);
793 793 }
794 794
795 795 midpm = usb_mid->mi_pm;
796 796
797 797 mutex_enter(&usb_mid->mi_mutex);
798 798
799 799 if ((midpm) && (usb_mid->mi_dev_state != USB_DEV_DISCONNECTED)) {
800 800
801 801 mutex_exit(&usb_mid->mi_mutex);
802 802
803 803 (void) pm_busy_component(dip, 0);
804 804 if (midpm->uc_wakeup_enabled) {
805 805
806 806 /* First bring the device to full power */
807 807 (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
808 808
809 809 rval = usb_handle_remote_wakeup(dip,
810 810 USB_REMOTE_WAKEUP_DISABLE);
811 811
812 812 if (rval != DDI_SUCCESS) {
813 813 USB_DPRINTF_L2(DPRINT_MASK_EVENTS,
814 814 usb_mid->mi_log_handle,
815 815 "usb_cleanup: disable remote "
816 816 "wakeup failed, rval=%d", rval);
817 817 }
818 818 }
819 819
820 820 (void) pm_lower_power(usb_mid->mi_dip, 0, USB_DEV_OS_PWR_OFF);
821 821 (void) pm_idle_component(dip, 0);
822 822 } else {
823 823 mutex_exit(&usb_mid->mi_mutex);
824 824 }
825 825
826 826 if (midpm) {
827 827 kmem_free(midpm, sizeof (usb_common_power_t));
828 828 }
829 829
830 830 /* free children list */
831 831 if (usb_mid->mi_children_dips) {
832 832 kmem_free(usb_mid->mi_children_dips,
833 833 usb_mid->mi_cd_list_length);
834 834 }
835 835
836 836 if (usb_mid->mi_child_events) {
837 837 kmem_free(usb_mid->mi_child_events, sizeof (uint8_t) *
838 838 usb_mid->mi_n_ifs);
839 839 }
840 840
841 841 if (usb_mid->mi_children_ifs) {
842 842 kmem_free(usb_mid->mi_children_ifs, sizeof (uint_t) *
843 843 usb_mid->mi_n_ifs);
844 844 }
845 845
846 846 if (usb_mid->mi_init_state & USB_MID_MINOR_NODE_CREATED) {
847 847 ddi_remove_minor_node(dip, NULL);
848 848 }
849 849
850 850 mutex_destroy(&usb_mid->mi_mutex);
851 851
852 852 done:
853 853 usb_client_detach(dip, usb_mid->mi_dev_data);
854 854
855 855 if (usb_mid->mi_ugen_hdl) {
856 856 (void) usb_ugen_detach(usb_mid->mi_ugen_hdl, DDI_DETACH);
857 857 usb_ugen_release_hdl(usb_mid->mi_ugen_hdl);
858 858 }
859 859
860 860 usb_free_log_hdl(usb_mid->mi_log_handle);
861 861 ddi_soft_state_free(usb_mid_statep, ddi_get_instance(dip));
862 862
863 863 ddi_prop_remove_all(dip);
864 864
865 865 return (DDI_SUCCESS);
866 866 }
867 867
868 868
869 869 static void
870 870 usb_mid_ugen_attach(usb_mid_t *usb_mid, boolean_t remove_children)
871 871 {
872 872 _NOTE(NO_COMPETING_THREADS_NOW);
873 873
874 874 if (usb_mid->mi_ugen_hdl == NULL) {
875 875 usb_ugen_info_t usb_ugen_info;
876 876 int rval;
877 877 usb_ugen_hdl_t hdl;
878 878
879 879 USB_DPRINTF_L4(DPRINT_MASK_ATTA, usb_mid->mi_log_handle,
880 880 "usb_mid_ugen_attach: get handle");
881 881
882 882 bzero(&usb_ugen_info, sizeof (usb_ugen_info));
883 883
884 884 usb_ugen_info.usb_ugen_flags = (remove_children ?
885 885 USB_UGEN_REMOVE_CHILDREN : 0);
886 886 usb_ugen_info.usb_ugen_minor_node_ugen_bits_mask =
887 887 (dev_t)USB_MID_MINOR_UGEN_BITS_MASK;
888 888 usb_ugen_info.usb_ugen_minor_node_instance_mask =
889 889 (dev_t)~USB_MID_MINOR_UGEN_BITS_MASK;
890 890
891 891 mutex_exit(&usb_mid->mi_mutex);
892 892 hdl = usb_ugen_get_hdl(usb_mid->mi_dip,
893 893 &usb_ugen_info);
894 894
895 895 if ((rval = usb_ugen_attach(hdl, DDI_ATTACH)) != USB_SUCCESS) {
896 896 USB_DPRINTF_L4(DPRINT_MASK_ATTA, usb_mid->mi_log_handle,
897 897 "failed to create ugen support (%d)", rval);
898 898 usb_ugen_release_hdl(hdl);
899 899
900 900 mutex_enter(&usb_mid->mi_mutex);
901 901 } else {
902 902 mutex_enter(&usb_mid->mi_mutex);
903 903 usb_mid->mi_ugen_hdl = hdl;
904 904 }
905 905 }
906 906
907 907 #ifndef lint
908 908 _NOTE(COMPETING_THREADS_NOW);
909 909 #endif
910 910 }
911 911
912 912
913 913 /*
914 914 * usb_mid_create_children:
915 915 */
916 916 static void
917 917 usb_mid_create_children(usb_mid_t *usb_mid)
918 918 {
919 919 usba_device_t *usba_device;
920 920 uint_t n_ifs, if_count;
921 921 uint_t i, j;
922 922 dev_info_t *cdip, *ia_dip;
923 923 uint_t ugen_bound = 0;
924 924 uint_t bound_children = 0;
925 925
926 926 usba_device = usba_get_usba_device(usb_mid->mi_dip);
927 927
928 928 USB_DPRINTF_L4(DPRINT_MASK_ATTA, usb_mid->mi_log_handle,
929 929 "usb_mid_attach_child_drivers: port = %d, address = %d",
930 930 usba_device->usb_port, usba_device->usb_addr);
931 931
932 932 if (usb_mid->mi_removed_children) {
933 933
934 934 return;
935 935 }
936 936
937 937 n_ifs = usb_mid->mi_n_ifs;
938 938 if_count = 1;
939 939
940 940 USB_DPRINTF_L4(DPRINT_MASK_ATTA, usb_mid->mi_log_handle,
941 941 "usb_mid_create_children: #interfaces = %d", n_ifs);
942 942
943 943 /*
944 944 * create all children if not already present
945 945 */
946 946 for (i = 0; i < n_ifs; i += if_count) {
947 947
948 948 /* ignore since this if is included by an ia */
949 949 if (usb_mid->mi_children_ifs[i] == 0) {
950 950
951 951 continue;
952 952 }
953 953
954 954 if (usb_mid->mi_children_dips[i] != NULL) {
955 955 if (i_ddi_node_state(
956 956 usb_mid->mi_children_dips[i]) >=
957 957 DS_BOUND) {
958 958 bound_children++;
959 959 }
960 960
961 961 continue;
962 962 }
963 963
964 964 mutex_exit(&usb_mid->mi_mutex);
965 965 ia_dip = usba_ready_interface_association_node(usb_mid->mi_dip,
966 966 i, &if_count);
967 967
968 968 if (ia_dip != NULL) {
969 969 if (usba_bind_driver(ia_dip) == USB_SUCCESS) {
970 970 bound_children++;
971 971 if (strcmp(ddi_driver_name(ia_dip),
972 972 "ugen") == 0) {
973 973 ugen_bound++;
974 974 }
975 975 }
976 976
977 977 /*
978 978 * IA node owns if_count interfaces.
979 979 * The rest interfaces own none.
980 980 */
981 981 mutex_enter(&usb_mid->mi_mutex);
982 982 usb_mid->mi_children_dips[i] = ia_dip;
983 983 usb_mid->mi_children_ifs[i] = if_count;
984 984 for (j = i + 1; j < i + if_count; j++) {
985 985 usb_mid->mi_children_ifs[j] = 0;
986 986 }
987 987
988 988 continue;
989 989 }
990 990
991 991 cdip = usba_ready_interface_node(usb_mid->mi_dip, i);
992 992
993 993 if (cdip != NULL) {
994 994 if (usba_bind_driver(cdip) ==
995 995 USB_SUCCESS) {
996 996 bound_children++;
997 997 if (strcmp(ddi_driver_name(cdip),
998 998 "ugen") == 0) {
999 999 ugen_bound++;
1000 1000 }
1001 1001 }
1002 1002
1003 1003 /*
1004 1004 * interface node owns 1 interface always.
1005 1005 */
1006 1006 mutex_enter(&usb_mid->mi_mutex);
1007 1007 usb_mid->mi_children_dips[i] = cdip;
1008 1008 usb_mid->mi_children_ifs[i] = 1;
1009 1009 mutex_exit(&usb_mid->mi_mutex);
1010 1010
1011 1011 }
1012 1012
1013 1013 mutex_enter(&usb_mid->mi_mutex);
1014 1014 }
1015 1015
1016 1016 usb_mid->mi_removed_children = (bound_children ? B_FALSE : B_TRUE);
1017 1017
1018 1018 /*
1019 1019 * if there are no ugen interface children, create ugen support at
1020 1020 * device level, use a separate thread because we may be at interrupt
1021 1021 * level
1022 1022 */
1023 1023 if ((ugen_bound == 0) && (usb_mid->mi_ugen_hdl == NULL)) {
1024 1024 /*
1025 1025 * we only need to remove the children if there are
1026 1026 * multiple configurations which would fail if there
1027 1027 * are child interfaces
1028 1028 */
1029 1029 if ((usb_mid->mi_removed_children == B_FALSE) &&
1030 1030 (usba_device->usb_n_cfgs > 1)) {
1031 1031 USB_DPRINTF_L1(DPRINT_MASK_ATTA,
1032 1032 usb_mid->mi_log_handle,
1033 1033 "can't support ugen for multiple "
1034 1034 "configurations devices that have attached "
1035 1035 "child interface drivers");
1036 1036 } else {
1037 1037 usb_mid_ugen_attach(usb_mid,
1038 1038 usb_mid->mi_removed_children);
1039 1039 }
1040 1040 }
1041 1041 }
1042 1042
1043 1043
1044 1044 /*
1045 1045 * event support
1046 1046 */
1047 1047 static int
1048 1048 usb_mid_busop_get_eventcookie(dev_info_t *dip,
1049 1049 dev_info_t *rdip, char *eventname, ddi_eventcookie_t *cookie)
1050 1050 {
1051 1051 usb_mid_t *usb_mid = usb_mid_obtain_state(dip);
1052 1052
1053 1053 USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_mid->mi_log_handle,
1054 1054 "usb_mid_busop_get_eventcookie: dip=0x%p, rdip=0x%p, "
1055 1055 "event=%s", (void *)dip, (void *)rdip, eventname);
1056 1056 USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_mid->mi_log_handle,
1057 1057 "(dip=%s%d rdip=%s%d)",
1058 1058 ddi_driver_name(dip), ddi_get_instance(dip),
1059 1059 ddi_driver_name(rdip), ddi_get_instance(rdip));
1060 1060
1061 1061 /* return event cookie, iblock cookie, and level */
1062 1062 return (ndi_event_retrieve_cookie(usb_mid->mi_ndi_event_hdl,
1063 1063 rdip, eventname, cookie, NDI_EVENT_NOPASS));
1064 1064 }
1065 1065
1066 1066
1067 1067 static int
1068 1068 usb_mid_busop_add_eventcall(dev_info_t *dip,
1069 1069 dev_info_t *rdip,
1070 1070 ddi_eventcookie_t cookie,
1071 1071 void (*callback)(dev_info_t *dip,
1072 1072 ddi_eventcookie_t cookie, void *arg,
1073 1073 void *bus_impldata),
1074 1074 void *arg, ddi_callback_id_t *cb_id)
1075 1075 {
1076 1076 usb_mid_t *usb_mid = usb_mid_obtain_state(dip);
1077 1077 int ifno = usba_get_ifno(rdip);
1078 1078
1079 1079 USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_mid->mi_log_handle,
1080 1080 "usb_mid_busop_add_eventcall: dip=0x%p, rdip=0x%p "
1081 1081 "cookie=0x%p, cb=0x%p, arg=0x%p",
1082 1082 (void *)dip, (void *)rdip, (void *)cookie, (void *)callback, arg);
1083 1083 USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_mid->mi_log_handle,
1084 1084 "(dip=%s%d rdip=%s%d event=%s)",
1085 1085 ddi_driver_name(dip), ddi_get_instance(dip),
1086 1086 ddi_driver_name(rdip), ddi_get_instance(rdip),
1087 1087 ndi_event_cookie_to_name(usb_mid->mi_ndi_event_hdl, cookie));
1088 1088
1089 1089 /* Set flag on children registering events */
1090 1090 switch (ndi_event_cookie_to_tag(usb_mid->mi_ndi_event_hdl, cookie)) {
1091 1091 case USBA_EVENT_TAG_HOT_REMOVAL:
1092 1092 mutex_enter(&usb_mid->mi_mutex);
1093 1093 usb_mid->mi_child_events[ifno] |=
1094 1094 USB_MID_CHILD_EVENT_DISCONNECT;
1095 1095 mutex_exit(&usb_mid->mi_mutex);
1096 1096
1097 1097 break;
1098 1098 case USBA_EVENT_TAG_PRE_SUSPEND:
1099 1099 mutex_enter(&usb_mid->mi_mutex);
1100 1100 usb_mid->mi_child_events[ifno] |=
1101 1101 USB_MID_CHILD_EVENT_PRESUSPEND;
1102 1102 mutex_exit(&usb_mid->mi_mutex);
1103 1103
1104 1104 break;
1105 1105 default:
1106 1106
1107 1107 break;
1108 1108 }
1109 1109 /* add callback (perform registration) */
1110 1110 return (ndi_event_add_callback(usb_mid->mi_ndi_event_hdl,
1111 1111 rdip, cookie, callback, arg, NDI_SLEEP, cb_id));
1112 1112 }
1113 1113
1114 1114
1115 1115 static int
1116 1116 usb_mid_busop_remove_eventcall(dev_info_t *dip, ddi_callback_id_t cb_id)
1117 1117 {
1118 1118 usb_mid_t *usb_mid = usb_mid_obtain_state(dip);
1119 1119 ndi_event_callbacks_t *cb = (ndi_event_callbacks_t *)cb_id;
1120 1120
1121 1121 ASSERT(cb);
1122 1122
1123 1123 USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_mid->mi_log_handle,
1124 1124 "usb_mid_busop_remove_eventcall: dip=0x%p, rdip=0x%p "
1125 1125 "cookie=0x%p", (void *)dip, (void *)cb->ndi_evtcb_dip,
1126 1126 (void *)cb->ndi_evtcb_cookie);
1127 1127 USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_mid->mi_log_handle,
1128 1128 "(dip=%s%d rdip=%s%d event=%s)",
1129 1129 ddi_driver_name(dip), ddi_get_instance(dip),
1130 1130 ddi_driver_name(cb->ndi_evtcb_dip),
1131 1131 ddi_get_instance(cb->ndi_evtcb_dip),
1132 1132 ndi_event_cookie_to_name(usb_mid->mi_ndi_event_hdl,
1133 1133 cb->ndi_evtcb_cookie));
1134 1134
1135 1135 /* remove event registration from our event set */
1136 1136 return (ndi_event_remove_callback(usb_mid->mi_ndi_event_hdl, cb_id));
1137 1137 }
1138 1138
1139 1139
1140 1140 static int
1141 1141 usb_mid_busop_post_event(dev_info_t *dip,
1142 1142 dev_info_t *rdip,
1143 1143 ddi_eventcookie_t cookie,
1144 1144 void *bus_impldata)
1145 1145 {
1146 1146 usb_mid_t *usb_mid = usb_mid_obtain_state(dip);
1147 1147
1148 1148 USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_mid->mi_log_handle,
1149 1149 "usb_mid_busop_post_event: dip=0x%p, rdip=0x%p "
1150 1150 "cookie=0x%p, impl=0x%p",
1151 1151 (void *)dip, (void *)rdip, (void *)cookie, bus_impldata);
1152 1152 USB_DPRINTF_L3(DPRINT_MASK_EVENTS, usb_mid->mi_log_handle,
1153 1153 "(dip=%s%d rdip=%s%d event=%s)",
1154 1154 ddi_driver_name(dip), ddi_get_instance(dip),
1155 1155 ddi_driver_name(rdip), ddi_get_instance(rdip),
1156 1156 ndi_event_cookie_to_name(usb_mid->mi_ndi_event_hdl, cookie));
1157 1157
1158 1158 /* post event to all children registered for this event */
1159 1159 return (ndi_event_run_callbacks(usb_mid->mi_ndi_event_hdl, rdip,
1160 1160 cookie, bus_impldata));
1161 1161 }
1162 1162
1163 1163
1164 1164 /*
1165 1165 * usb_mid_restore_device_state
1166 1166 * set the original configuration of the device
1167 1167 */
1168 1168 static int
1169 1169 usb_mid_restore_device_state(dev_info_t *dip, usb_mid_t *usb_mid)
1170 1170 {
1171 1171 usb_common_power_t *midpm;
1172 1172
1173 1173 USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_mid->mi_log_handle,
1174 1174 "usb_mid_restore_device_state: usb_mid = %p", (void *)usb_mid);
1175 1175
1176 1176 mutex_enter(&usb_mid->mi_mutex);
1177 1177 midpm = usb_mid->mi_pm;
1178 1178 mutex_exit(&usb_mid->mi_mutex);
1179 1179
1180 1180 /* First bring the device to full power */
1181 1181 (void) pm_busy_component(dip, 0);
1182 1182 (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
1183 1183
1184 1184 if (usb_check_same_device(dip, usb_mid->mi_log_handle, USB_LOG_L0,
1185 1185 DPRINT_MASK_EVENTS, USB_CHK_VIDPID, NULL) != USB_SUCCESS) {
1186 1186
1187 1187 /* change the device state from suspended to disconnected */
1188 1188 mutex_enter(&usb_mid->mi_mutex);
1189 1189 usb_mid->mi_dev_state = USB_DEV_DISCONNECTED;
1190 1190 mutex_exit(&usb_mid->mi_mutex);
1191 1191 (void) pm_idle_component(dip, 0);
1192 1192
1193 1193 return (USB_FAILURE);
1194 1194 }
1195 1195
1196 1196 /*
1197 1197 * if the device had remote wakeup earlier,
1198 1198 * enable it again
1199 1199 */
1200 1200 if (midpm->uc_wakeup_enabled) {
1201 1201 (void) usb_handle_remote_wakeup(usb_mid->mi_dip,
1202 1202 USB_REMOTE_WAKEUP_ENABLE);
1203 1203 }
1204 1204
1205 1205 mutex_enter(&usb_mid->mi_mutex);
1206 1206 usb_mid->mi_dev_state = USB_DEV_ONLINE;
1207 1207 mutex_exit(&usb_mid->mi_mutex);
1208 1208
1209 1209 (void) pm_idle_component(dip, 0);
1210 1210
1211 1211 return (USB_SUCCESS);
1212 1212 }
1213 1213
1214 1214
1215 1215 /*
1216 1216 * usb_mid_event_cb()
1217 1217 * handle disconnect and connect events
1218 1218 */
1219 1219 static void
1220 1220 usb_mid_event_cb(dev_info_t *dip, ddi_eventcookie_t cookie,
1221 1221 void *arg, void *bus_impldata)
1222 1222 {
1223 1223 int i, tag;
1224 1224 usb_mid_t *usb_mid = usb_mid_obtain_state(dip);
1225 1225 dev_info_t *child_dip;
1226 1226 ddi_eventcookie_t rm_cookie, ins_cookie, suspend_cookie, resume_cookie;
1227 1227
1228 1228 USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_mid->mi_log_handle,
1229 1229 "usb_mid_event_cb: dip=0x%p, cookie=0x%p, "
1230 1230 "arg=0x%p, impl=0x%p",
1231 1231 (void *)dip, (void *)cookie, arg, bus_impldata);
1232 1232 USB_DPRINTF_L4(DPRINT_MASK_EVENTS, usb_mid->mi_log_handle,
1233 1233 "(dip=%s%d event=%s)",
1234 1234 ddi_driver_name(dip), ddi_get_instance(dip),
1235 1235 ndi_event_cookie_to_name(usb_mid->mi_ndi_event_hdl, cookie));
1236 1236
1237 1237 tag = NDI_EVENT_TAG(cookie);
1238 1238 rm_cookie = ndi_event_tag_to_cookie(
1239 1239 usb_mid->mi_ndi_event_hdl, USBA_EVENT_TAG_HOT_REMOVAL);
1240 1240 suspend_cookie = ndi_event_tag_to_cookie(
1241 1241 usb_mid->mi_ndi_event_hdl, USBA_EVENT_TAG_PRE_SUSPEND);
1242 1242 ins_cookie = ndi_event_tag_to_cookie(
1243 1243 usb_mid->mi_ndi_event_hdl, USBA_EVENT_TAG_HOT_INSERTION);
1244 1244 resume_cookie = ndi_event_tag_to_cookie(
1245 1245 usb_mid->mi_ndi_event_hdl, USBA_EVENT_TAG_POST_RESUME);
1246 1246
1247 1247 mutex_enter(&usb_mid->mi_mutex);
1248 1248 switch (tag) {
1249 1249 case USBA_EVENT_TAG_HOT_REMOVAL:
1250 1250 if (usb_mid->mi_dev_state == USB_DEV_DISCONNECTED) {
1251 1251 USB_DPRINTF_L2(DPRINT_MASK_EVENTS,
1252 1252 usb_mid->mi_log_handle,
1253 1253 "usb_mid_event_cb: Device already disconnected");
1254 1254 } else {
1255 1255 /* we are disconnected so set our state now */
1256 1256 usb_mid->mi_dev_state = USB_DEV_DISCONNECTED;
1257 1257 for (i = 0; i < usb_mid->mi_n_ifs; i++) {
1258 1258 usb_mid->mi_child_events[i] &= ~
1259 1259 USB_MID_CHILD_EVENT_DISCONNECT;
1260 1260 }
1261 1261 mutex_exit(&usb_mid->mi_mutex);
1262 1262
1263 1263 /* pass disconnect event to all the children */
1264 1264 (void) ndi_event_run_callbacks(
1265 1265 usb_mid->mi_ndi_event_hdl, NULL,
1266 1266 rm_cookie, bus_impldata);
1267 1267
1268 1268 if (usb_mid->mi_ugen_hdl) {
1269 1269 (void) usb_ugen_disconnect_ev_cb(
1270 1270 usb_mid->mi_ugen_hdl);
1271 1271 }
1272 1272 mutex_enter(&usb_mid->mi_mutex);
1273 1273 }
1274 1274 break;
1275 1275 case USBA_EVENT_TAG_PRE_SUSPEND:
1276 1276 /* set our state *after* suspending children */
1277 1277 mutex_exit(&usb_mid->mi_mutex);
1278 1278
1279 1279 /* pass pre_suspend event to all the children */
1280 1280 (void) ndi_event_run_callbacks(usb_mid->mi_ndi_event_hdl,
1281 1281 NULL, suspend_cookie, bus_impldata);
1282 1282
1283 1283 mutex_enter(&usb_mid->mi_mutex);
1284 1284 for (i = 0; i < usb_mid->mi_n_ifs; i++) {
1285 1285 usb_mid->mi_child_events[i] &= ~
1286 1286 USB_MID_CHILD_EVENT_PRESUSPEND;
1287 1287 }
1288 1288 break;
1289 1289 case USBA_EVENT_TAG_HOT_INSERTION:
1290 1290 mutex_exit(&usb_mid->mi_mutex);
1291 1291 if (usb_mid_restore_device_state(dip, usb_mid) == USB_SUCCESS) {
1292 1292
1293 1293 /*
1294 1294 * Check to see if this child has missed the disconnect
1295 1295 * event before it registered for event cb
1296 1296 */
1297 1297 mutex_enter(&usb_mid->mi_mutex);
1298 1298 for (i = 0; i < usb_mid->mi_n_ifs; i++) {
1299 1299 if ((usb_mid->mi_child_events[i] &
1300 1300 USB_MID_CHILD_EVENT_DISCONNECT) &&
1301 1301 usb_mid->mi_children_ifs[i]) {
1302 1302 usb_mid->mi_child_events[i] &=
1303 1303 ~USB_MID_CHILD_EVENT_DISCONNECT;
1304 1304 child_dip =
1305 1305 usb_mid->mi_children_dips[i];
1306 1306 mutex_exit(&usb_mid->mi_mutex);
1307 1307
1308 1308 /* post the missed disconnect */
1309 1309 (void) ndi_event_do_callback(
1310 1310 usb_mid->mi_ndi_event_hdl,
1311 1311 child_dip,
1312 1312 rm_cookie,
1313 1313 bus_impldata);
1314 1314 mutex_enter(&usb_mid->mi_mutex);
1315 1315 }
1316 1316 }
1317 1317 mutex_exit(&usb_mid->mi_mutex);
1318 1318
1319 1319 /* pass reconnect event to all the children */
1320 1320 (void) ndi_event_run_callbacks(
1321 1321 usb_mid->mi_ndi_event_hdl, NULL,
1322 1322 ins_cookie, bus_impldata);
1323 1323
1324 1324 if (usb_mid->mi_ugen_hdl) {
1325 1325 (void) usb_ugen_reconnect_ev_cb(
1326 1326 usb_mid->mi_ugen_hdl);
1327 1327 }
1328 1328 }
1329 1329 mutex_enter(&usb_mid->mi_mutex);
1330 1330 break;
1331 1331 case USBA_EVENT_TAG_POST_RESUME:
1332 1332 /*
1333 1333 * Check to see if this child has missed the pre-suspend
1334 1334 * event before it registered for event cb
1335 1335 */
1336 1336 for (i = 0; i < usb_mid->mi_n_ifs; i++) {
1337 1337 if ((usb_mid->mi_child_events[i] &
1338 1338 USB_MID_CHILD_EVENT_PRESUSPEND) &&
1339 1339 usb_mid->mi_children_ifs[i]) {
1340 1340 usb_mid->mi_child_events[i] &=
1341 1341 ~USB_MID_CHILD_EVENT_PRESUSPEND;
1342 1342 child_dip = usb_mid->mi_children_dips[i];
1343 1343 mutex_exit(&usb_mid->mi_mutex);
1344 1344
1345 1345 /* post the missed pre-suspend event */
1346 1346 (void) ndi_event_do_callback(
1347 1347 usb_mid->mi_ndi_event_hdl,
1348 1348 child_dip, suspend_cookie,
1349 1349 bus_impldata);
1350 1350 mutex_enter(&usb_mid->mi_mutex);
1351 1351 }
1352 1352 }
1353 1353 mutex_exit(&usb_mid->mi_mutex);
1354 1354
1355 1355 /* pass post_resume event to all the children */
1356 1356 (void) ndi_event_run_callbacks(usb_mid->mi_ndi_event_hdl,
1357 1357 NULL, resume_cookie, bus_impldata);
1358 1358
1359 1359 mutex_enter(&usb_mid->mi_mutex);
1360 1360 break;
1361 1361 }
1362 1362 mutex_exit(&usb_mid->mi_mutex);
1363 1363
1364 1364 }
1365 1365
1366 1366
1367 1367 /*
1368 1368 * create the pm components required for power management
1369 1369 */
1370 1370 static void
1371 1371 usb_mid_create_pm_components(dev_info_t *dip, usb_mid_t *usb_mid)
1372 1372 {
1373 1373 usb_common_power_t *midpm;
1374 1374 uint_t pwr_states;
1375 1375
1376 1376 USB_DPRINTF_L4(DPRINT_MASK_PM, usb_mid->mi_log_handle,
1377 1377 "usb_mid_create_pm_components: Begin");
1378 1378
1379 1379 /* Allocate the PM state structure */
1380 1380 midpm = kmem_zalloc(sizeof (usb_common_power_t), KM_SLEEP);
1381 1381
1382 1382 mutex_enter(&usb_mid->mi_mutex);
1383 1383 usb_mid->mi_pm = midpm;
1384 1384 midpm->uc_usb_statep = usb_mid;
1385 1385 midpm->uc_pm_capabilities = 0; /* XXXX should this be 0?? */
1386 1386 midpm->uc_current_power = USB_DEV_OS_FULL_PWR;
1387 1387 mutex_exit(&usb_mid->mi_mutex);
1388 1388
1389 1389 /*
1390 1390 * By not enabling parental notification, PM enforces
1391 1391 * "strict parental dependency" meaning, usb_mid won't
1392 1392 * power off until any of its children are in full power.
1393 1393 */
1394 1394
1395 1395 /*
1396 1396 * there are 3 scenarios:
1397 1397 * 1. a well behaved device should have remote wakeup
1398 1398 * at interface and device level. If the interface
1399 1399 * wakes up, usb_mid will wake up
1400 1400 * 2. if the device doesn't have remote wake up and
1401 1401 * the interface has, PM will still work, ie.
1402 1402 * the interfaces wakes up and usb_mid wakes up
1403 1403 * 3. if neither the interface nor device has remote
1404 1404 * wakeup, the interface will wake up when it is opened
1405 1405 * and goes to sleep after being closed for a while
1406 1406 * In this case usb_mid should also go to sleep shortly
1407 1407 * thereafter
1408 1408 * In all scenarios it doesn't really matter whether
1409 1409 * remote wakeup at the device level is enabled or not
1410 1410 * but we do it anyways
1411 1411 */
1412 1412 if (usb_handle_remote_wakeup(dip, USB_REMOTE_WAKEUP_ENABLE) ==
1413 1413 USB_SUCCESS) {
1414 1414 USB_DPRINTF_L3(DPRINT_MASK_PM, usb_mid->mi_log_handle,
1415 1415 "usb_mid_create_pm_components: "
1416 1416 "Remote Wakeup Enabled");
1417 1417 midpm->uc_wakeup_enabled = 1;
1418 1418 }
1419 1419
1420 1420 if (usb_create_pm_components(dip, &pwr_states) ==
1421 1421 USB_SUCCESS) {
1422 1422 midpm->uc_pwr_states = (uint8_t)pwr_states;
1423 1423 (void) pm_raise_power(dip, 0, USB_DEV_OS_FULL_PWR);
1424 1424 }
1425 1425
1426 1426 USB_DPRINTF_L4(DPRINT_MASK_PM, usb_mid->mi_log_handle,
1427 1427 "usb_mid_create_pm_components: End");
1428 1428 }
1429 1429
1430 1430
1431 1431 /*
1432 1432 * usb_mid_obtain_state:
1433 1433 */
1434 1434 usb_mid_t *
1435 1435 usb_mid_obtain_state(dev_info_t *dip)
1436 1436 {
1437 1437 int instance = ddi_get_instance(dip);
1438 1438 usb_mid_t *statep = ddi_get_soft_state(usb_mid_statep, instance);
1439 1439
1440 1440 ASSERT(statep != NULL);
1441 1441
1442 1442 return (statep);
1443 1443 }
1444 1444
1445 1445
1446 1446 /*
1447 1447 * ugen support
1448 1448 */
1449 1449 /* ARGSUSED3 */
1450 1450 static int
1451 1451 usb_mid_open(dev_t *devp, int flags, int otyp, cred_t *credp)
1452 1452 {
1453 1453 struct usb_mid *usb_mid;
1454 1454 int rval;
1455 1455
1456 1456 if ((usb_mid = ddi_get_soft_state(usb_mid_statep,
1457 1457 USB_MID_MINOR_TO_INSTANCE(getminor(*devp)))) == NULL) {
1458 1458
1459 1459 return (ENXIO);
1460 1460 }
1461 1461
1462 1462 USB_DPRINTF_L4(DPRINT_MASK_CBOPS, usb_mid->mi_log_handle,
1463 1463 "usb_mid_open: usb_mid = 0x%p *devp = 0x%lx",
1464 1464 (void *)usb_mid, *devp);
1465 1465
1466 1466 /* First bring the device to full power */
1467 1467 (void) pm_busy_component(usb_mid->mi_dip, 0);
1468 1468 (void) pm_raise_power(usb_mid->mi_dip, 0, USB_DEV_OS_FULL_PWR);
1469 1469
1470 1470
1471 1471 rval = usb_ugen_open(usb_mid->mi_ugen_hdl, devp, flags, otyp,
1472 1472 credp);
1473 1473 if (rval) {
1474 1474 (void) pm_idle_component(usb_mid->mi_dip, 0);
1475 1475 } else {
1476 1476 /*
1477 1477 * since all ugen opens are exclusive we can count the
1478 1478 * opens
1479 1479 */
1480 1480 mutex_enter(&usb_mid->mi_mutex);
1481 1481 usb_mid->mi_ugen_open_count++;
1482 1482 mutex_exit(&usb_mid->mi_mutex);
1483 1483 }
1484 1484
1485 1485 return (rval);
1486 1486 }
1487 1487
1488 1488
1489 1489 /* ARGSUSED */
1490 1490 static int
1491 1491 usb_mid_close(dev_t dev, int flag, int otyp, cred_t *credp)
1492 1492 {
1493 1493 struct usb_mid *usb_mid;
1494 1494 int rval;
1495 1495
1496 1496 if ((usb_mid = ddi_get_soft_state(usb_mid_statep,
1497 1497 USB_MID_MINOR_TO_INSTANCE(getminor(dev)))) == NULL) {
1498 1498
1499 1499 return (ENXIO);
1500 1500 }
1501 1501
1502 1502 rval = usb_ugen_close(usb_mid->mi_ugen_hdl, dev, flag, otyp,
1503 1503 credp);
1504 1504 if (rval == 0) {
1505 1505 (void) pm_idle_component(usb_mid->mi_dip, 0);
1506 1506 mutex_enter(&usb_mid->mi_mutex);
1507 1507 usb_mid->mi_ugen_open_count--;
1508 1508 mutex_exit(&usb_mid->mi_mutex);
1509 1509 }
1510 1510
1511 1511 return (rval);
1512 1512 }
1513 1513
1514 1514
1515 1515 static int
1516 1516 usb_mid_read(dev_t dev, struct uio *uio, cred_t *credp)
1517 1517 {
1518 1518 struct usb_mid *usb_mid;
1519 1519
1520 1520 if ((usb_mid = ddi_get_soft_state(usb_mid_statep,
1521 1521 USB_MID_MINOR_TO_INSTANCE(getminor(dev)))) == NULL) {
1522 1522
1523 1523 return (ENXIO);
1524 1524 }
1525 1525
1526 1526 return (usb_ugen_read(usb_mid->mi_ugen_hdl, dev, uio, credp));
1527 1527 }
1528 1528
1529 1529
1530 1530 static int
1531 1531 usb_mid_write(dev_t dev, struct uio *uio, cred_t *credp)
1532 1532 {
1533 1533 struct usb_mid *usb_mid;
1534 1534
1535 1535 if ((usb_mid = ddi_get_soft_state(usb_mid_statep,
1536 1536 USB_MID_MINOR_TO_INSTANCE(getminor(dev)))) == NULL) {
1537 1537
1538 1538 return (ENXIO);
1539 1539 }
1540 1540
1541 1541 return (usb_ugen_write(usb_mid->mi_ugen_hdl, dev, uio, credp));
1542 1542 }
1543 1543
1544 1544
1545 1545 static int
1546 1546 usb_mid_poll(dev_t dev, short events, int anyyet, short *reventsp,
1547 1547 struct pollhead **phpp)
1548 1548 {
1549 1549 struct usb_mid *usb_mid;
1550 1550
1551 1551 if ((usb_mid = ddi_get_soft_state(usb_mid_statep,
1552 1552 USB_MID_MINOR_TO_INSTANCE(getminor(dev)))) == NULL) {
1553 1553
1554 1554 return (ENXIO);
1555 1555 }
1556 1556
1557 1557 return (usb_ugen_poll(usb_mid->mi_ugen_hdl, dev, events,
1558 1558 anyyet, reventsp, phpp));
1559 1559 }
↓ open down ↓ |
1354 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX