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