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