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 
27 /*
28  * Open Host Controller Driver (OHCI)
29  *
30  * The USB Open Host Controller driver is a software driver which interfaces
31  * to the Universal Serial Bus layer (USBA) and the USB Open Host Controller.
32  * The interface to USB Open Host Controller is defined by the OpenHCI	Host
33  * Controller Interface.
34  *
35  * This module contains the code for root hub related functions.
36  *
37  * Note: ONE_XFER is not supported on root hub interrupt polling.
38  */
39 #include <sys/usb/hcd/openhci/ohcid.h>
40 
41 /* static function prototypes */
42 static int	ohci_handle_set_clear_port_feature(
43 				ohci_state_t		*ohcip,
44 				uchar_t 		bRequest,
45 				uint16_t		wValue,
46 				uint16_t		port);
47 static void	ohci_handle_port_power(ohci_state_t	*ohcip,
48 				uint16_t		port,
49 				uint_t			on);
50 static void	ohci_handle_port_enable(ohci_state_t	*ohcip,
51 				uint16_t		port,
52 				uint_t			on);
53 static void	ohci_handle_clrchng_port_enable(
54 				ohci_state_t		*ohcip,
55 				uint16_t		port);
56 static void	ohci_handle_port_suspend(ohci_state_t	*ohcip,
57 				uint16_t		port,
58 				uint_t			on);
59 static void	ohci_handle_clrchng_port_suspend(
60 				ohci_state_t		*ohcip,
61 				uint16_t		port);
62 static void	ohci_handle_port_reset(ohci_state_t	*ohcip,
63 				uint16_t		port);
64 static void	ohci_handle_complete_port_reset(
65 				ohci_state_t		*ohcip,
66 				uint16_t		port);
67 static void	ohci_handle_clear_port_connection(
68 				ohci_state_t		*ohcip,
69 				uint16_t		port);
70 static void	ohci_handle_clrchng_port_over_current(
71 				ohci_state_t		*ohcip,
72 				uint16_t		port);
73 static void	ohci_handle_get_port_status(
74 				ohci_state_t		*ohcip,
75 				uint16_t		port);
76 static int	ohci_handle_set_clear_hub_feature(
77 				ohci_state_t		*ohcip,
78 				uchar_t 		bRequest,
79 				uint16_t		wValue);
80 static void	ohci_handle_clrchng_hub_over_current(
81 				ohci_state_t		*ohcip);
82 static void	ohci_handle_get_hub_descriptor(
83 				ohci_state_t		*ohcip);
84 static void	ohci_handle_get_hub_status(
85 				ohci_state_t		*ohcip);
86 static void	ohci_handle_get_device_status(
87 				ohci_state_t		*ohcip);
88 static int	ohci_root_hub_allocate_intr_pipe_resource(
89 				ohci_state_t		*ohcip,
90 				usb_flags_t		flags);
91 static void	ohci_root_hub_intr_pipe_cleanup(
92 				ohci_state_t		*ohcip,
93 				usb_cr_t		completion_reason);
94 static void	ohci_root_hub_hcdi_callback(
95 				usba_pipe_handle_data_t	*ph,
96 				usb_cr_t		completion_reason);
97 
98 
99 /*
100  * ohci_init_root_hub:
101  *
102  * Initialize the root hub
103  */
104 int
ohci_init_root_hub(ohci_state_t * ohcip)105 ohci_init_root_hub(ohci_state_t	*ohcip)
106 {
107 	usb_hub_descr_t 	*root_hub_descr =
108 	    &ohcip->ohci_root_hub.rh_descr;
109 	uint_t			des_A, des_B, port_state;
110 	int			i, length;
111 
112 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
113 	    "ohci_init_root_hub:");
114 
115 	/* Read the descriptor registers */
116 	des_A = ohcip->ohci_root_hub.rh_des_A = Get_OpReg(hcr_rh_descriptorA);
117 	des_B = ohcip->ohci_root_hub.rh_des_B = Get_OpReg(hcr_rh_descriptorB);
118 
119 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
120 	    "root hub descriptor A 0x%x", ohcip->ohci_root_hub.rh_des_A);
121 
122 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
123 	    "root hub descriptor B 0x%x", ohcip->ohci_root_hub.rh_des_B);
124 
125 	/* Obtain the root hub status */
126 	ohcip->ohci_root_hub.rh_status = Get_OpReg(hcr_rh_status);
127 
128 	/*
129 	 * Build the hub descriptor based on HcRhDescriptorA and
130 	 * HcRhDescriptorB
131 	 */
132 	root_hub_descr->bDescriptorType = ROOT_HUB_DESCRIPTOR_TYPE;
133 
134 	if ((des_A & HCR_RHA_NDP) > OHCI_MAX_RH_PORTS) {
135 		USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
136 		    "ohci_init_root_hub:" "Invalid no of root hub ports 0x%x",
137 		    des_A & HCR_RHA_NDP);
138 
139 		return (USB_FAILURE);
140 	}
141 
142 	/* Obtain the number of downstream ports */
143 	root_hub_descr->bNbrPorts = des_A & HCR_RHA_NDP;
144 
145 	length = root_hub_descr->bNbrPorts / 8;
146 
147 	if (length) {
148 		root_hub_descr->bDescLength = 7 + (2 * (length + 1));
149 	} else {
150 		root_hub_descr->bDescLength = ROOT_HUB_DESCRIPTOR_LENGTH;
151 	}
152 
153 	/* Determine the Power Switching Mode */
154 	if (!(des_A & HCR_RHA_NPS)) {
155 		/*
156 		 * The ports are power switched. Check for either individual
157 		 * or gang power switching.
158 		 */
159 		if ((des_A & HCR_RHA_PSM) && (des_B & HCR_RHB_PPCM)) {
160 			/* each port is powered individually */
161 			root_hub_descr->wHubCharacteristics =
162 			    HUB_CHARS_INDIVIDUAL_PORT_POWER;
163 		} else {
164 			/* the ports are gang powered */
165 			root_hub_descr->
166 			    wHubCharacteristics = HUB_CHARS_GANGED_POWER;
167 		}
168 
169 		/* Each port will start off in the POWERED_OFF mode */
170 		port_state = POWERED_OFF;
171 	} else {
172 		/* The ports are powered when the ctlr is powered */
173 		root_hub_descr->
174 		    wHubCharacteristics = HUB_CHARS_NO_POWER_SWITCHING;
175 
176 		port_state = DISCONNECTED;
177 	}
178 
179 	/* The root hub should never be a compound device */
180 	ASSERT((des_A & HCR_RHA_DT) == 0);
181 
182 	/* Determine the Over-current Protection Mode */
183 	if (des_A & HCR_RHA_NOCP) {
184 		/* No over current protection */
185 		root_hub_descr->
186 		    wHubCharacteristics |= HUB_CHARS_NO_OVER_CURRENT;
187 	} else {
188 		USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB,
189 		    ohcip->ohci_log_hdl, "OCPM =%d, PSM=%d",
190 		    des_A & HCR_RHA_OCPM, des_A & HCR_RHA_PSM);
191 
192 		/* See if over current protection is provided */
193 		if (des_A & HCR_RHA_OCPM) {
194 			/* reported on a per port basis */
195 			root_hub_descr->
196 			    wHubCharacteristics |= HUB_CHARS_INDIV_OVER_CURRENT;
197 		}
198 	}
199 
200 	/* Obtain the power on to power good time of the ports */
201 	root_hub_descr->bPwrOn2PwrGood = (uint32_t)
202 	    ((des_A & HCR_RHA_PTPGT) >> HCR_RHA_PTPGT_SHIFT);
203 
204 	USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
205 	    "Power on to power good %d", root_hub_descr->bPwrOn2PwrGood);
206 
207 	/* Indicate if the device is removable */
208 	root_hub_descr->DeviceRemovable = (uchar_t)des_B & HCR_RHB_DR;
209 
210 	/*
211 	 * Fill in the port power control mask:
212 	 * Each bit in the  PortPowerControlMask
213 	 * should be set. Refer to USB 2.0, table 11-13
214 	 */
215 	root_hub_descr->PortPwrCtrlMask = (uchar_t)(des_B >> 16);
216 
217 	/* Set the state of each port and initialize the status */
218 	for (i = 0; i < root_hub_descr->bNbrPorts; i++) {
219 		ohcip->ohci_root_hub.rh_port_state[i] = port_state;
220 
221 		/* Turn off the power on each port for now */
222 		Set_OpReg(hcr_rh_portstatus[i],  HCR_PORT_CPP);
223 
224 		/*
225 		 * Initialize each of the root hub port	status
226 		 * equal to zero. This initialization makes sure
227 		 * that all devices connected to root hub will
228 		 * enumerates when the first RHSC interrupt occurs
229 		 * since definitely there will be changes  in
230 		 * the root hub port status.
231 		 */
232 		ohcip->ohci_root_hub.rh_port_status[i] = 0;
233 	}
234 
235 	return (USB_SUCCESS);
236 }
237 
238 
239 /*
240  * ohci_load_root_hub_driver:
241  *
242  * Attach the root hub
243  */
244 static usb_dev_descr_t ohci_root_hub_device_descriptor = {
245 	0x12,		/* bLength */
246 	0x01,		/* bDescriptorType, Device */
247 	0x110,		/* bcdUSB, v1.1 */
248 	0x09,		/* bDeviceClass */
249 	0x00,		/* bDeviceSubClass */
250 	0x00,		/* bDeviceProtocol */
251 	0x08,		/* bMaxPacketSize0 */
252 	0x00,		/* idVendor */
253 	0x00,		/* idProduct */
254 	0x00,		/* bcdDevice */
255 	0x00,		/* iManufacturer */
256 	0x00,		/* iProduct */
257 	0x00,		/* iSerialNumber */
258 	0x01		/* bNumConfigurations */
259 };
260 
261 static uchar_t ohci_root_hub_config_descriptor[] = {
262 	/* One configuartion */
263 	0x09,		/* bLength */
264 	0x02,		/* bDescriptorType, Configuartion */
265 	0x19, 0x00,	/* wTotalLength */
266 	0x01,		/* bNumInterfaces */
267 	0x01,		/* bConfigurationValue */
268 	0x00,		/* iConfiguration */
269 	0x40,		/* bmAttributes */
270 	0x00,		/* MaxPower */
271 
272 	/* One Interface */
273 	0x09,		/* bLength */
274 	0x04,		/* bDescriptorType, Interface */
275 	0x00,		/* bInterfaceNumber */
276 	0x00,		/* bAlternateSetting */
277 	0x01,		/* bNumEndpoints */
278 	0x09,		/* bInterfaceClass */
279 	0x01,		/* bInterfaceSubClass */
280 	0x00,		/* bInterfaceProtocol */
281 	0x00,		/* iInterface */
282 
283 	/* One Endpoint (status change endpoint) */
284 	0x07,		/* bLength */
285 	0x05,		/* bDescriptorType, Endpoint */
286 	0x81,		/* bEndpointAddress */
287 	0x03,		/* bmAttributes */
288 	0x01, 0x00,	/* wMaxPacketSize, 1 +	(OHCI_MAX_RH_PORTS / 8) */
289 	0xff		/* bInterval */
290 };
291 
292 int
ohci_load_root_hub_driver(ohci_state_t * ohcip)293 ohci_load_root_hub_driver(ohci_state_t	*ohcip)
294 {
295 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
296 	    "ohci_load_root_hub_driver:");
297 
298 	return (usba_hubdi_bind_root_hub(ohcip->ohci_dip,
299 	    ohci_root_hub_config_descriptor,
300 	    sizeof (ohci_root_hub_config_descriptor),
301 	    &ohci_root_hub_device_descriptor));
302 }
303 
304 
305 /*
306  * ohci_unload_root_hub_driver:
307  */
308 int
ohci_unload_root_hub_driver(ohci_state_t * ohcip)309 ohci_unload_root_hub_driver(ohci_state_t	*ohcip)
310 {
311 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
312 	    "ohci_unload_root_hub_driver:");
313 
314 	return (usba_hubdi_unbind_root_hub(ohcip->ohci_dip));
315 }
316 
317 
318 /*
319  * ohci_handle_root_hub_pipe_open:
320  *
321  * Handle opening of control and interrupt pipes on root hub.
322  */
323 /* ARGSUSED */
324 int
ohci_handle_root_hub_pipe_open(usba_pipe_handle_data_t * ph,usb_flags_t usb_flags)325 ohci_handle_root_hub_pipe_open(
326 	usba_pipe_handle_data_t	*ph,
327 	usb_flags_t		usb_flags)
328 {
329 	ohci_state_t		*ohcip = ohci_obtain_state(
330 	    ph->p_usba_device->usb_root_hub_dip);
331 	usb_ep_descr_t		*eptd = &ph->p_ep;
332 
333 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
334 	    "ohci_handle_root_hub_pipe_open: Root hub pipe open");
335 
336 	ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
337 
338 	switch (eptd->bmAttributes & USB_EP_ATTR_MASK) {
339 	case USB_EP_ATTR_CONTROL:
340 		/* Save control pipe handle */
341 		ohcip->ohci_root_hub.rh_ctrl_pipe_handle = ph;
342 
343 		/* Set state of the root hub control pipe as idle */
344 		ohcip->ohci_root_hub.rh_ctrl_pipe_state = OHCI_PIPE_STATE_IDLE;
345 
346 		ohcip->ohci_root_hub.rh_curr_ctrl_reqp = NULL;
347 
348 		USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
349 		    "ohci_handle_root_hub_pipe_open: Root hub control "
350 		    "pipe open succeeded");
351 
352 		break;
353 	case USB_EP_ATTR_INTR:
354 		/* Save interrupt pipe handle */
355 		ohcip->ohci_root_hub.rh_intr_pipe_handle = ph;
356 
357 		/* Set state of the root hub interrupt pipe as idle */
358 		ohcip->ohci_root_hub.rh_intr_pipe_state = OHCI_PIPE_STATE_IDLE;
359 
360 		ohcip->ohci_root_hub.rh_client_intr_reqp = NULL;
361 
362 		ohcip->ohci_root_hub.rh_curr_intr_reqp = NULL;
363 
364 		USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
365 		    "ohci_handle_root_hub_pipe_open: Root hub interrupt "
366 		    "pipe open succeeded");
367 
368 		break;
369 	default:
370 		USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
371 		    "ohci_handle_root_hub_pipe_open: Root hub pipe open"
372 		    "failed");
373 
374 		return (USB_FAILURE);
375 	}
376 
377 	ohcip->ohci_open_pipe_count++;
378 
379 	return (USB_SUCCESS);
380 }
381 
382 
383 /*
384  * ohci_handle_root_hub_pipe_close:
385  *
386  * Handle closing of control and interrupt pipes on root hub.
387  */
388 /* ARGSUSED */
389 int
ohci_handle_root_hub_pipe_close(usba_pipe_handle_data_t * ph)390 ohci_handle_root_hub_pipe_close(usba_pipe_handle_data_t	*ph)
391 {
392 	ohci_state_t		*ohcip = ohci_obtain_state(
393 	    ph->p_usba_device->usb_root_hub_dip);
394 	usb_ep_descr_t		*eptd = &ph->p_ep;
395 
396 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
397 	    "ohci_handle_root_hub_pipe_close: Root hub pipe close");
398 
399 	ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
400 
401 	switch (eptd->bmAttributes & USB_EP_ATTR_MASK) {
402 	case USB_EP_ATTR_CONTROL:
403 		ASSERT(ohcip->ohci_root_hub.
404 		    rh_ctrl_pipe_state != OHCI_PIPE_STATE_CLOSE);
405 
406 		/* Set state of the root hub control pipe as close */
407 		ohcip->ohci_root_hub.rh_ctrl_pipe_state = OHCI_PIPE_STATE_CLOSE;
408 
409 		/* Set root hub control pipe handle to null */
410 		ohcip->ohci_root_hub.rh_ctrl_pipe_handle = NULL;
411 
412 		USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
413 		    "ohci_handle_root_hub_pipe_close: "
414 		    "Root hub control pipe close succeeded");
415 		break;
416 	case USB_EP_ATTR_INTR:
417 		ASSERT((eptd->bEndpointAddress & USB_EP_NUM_MASK) == 1);
418 
419 		ASSERT(ohcip->ohci_root_hub.
420 		    rh_intr_pipe_state != OHCI_PIPE_STATE_CLOSE);
421 
422 		/* Set state of the root hub interrupt pipe as close */
423 		ohcip->ohci_root_hub.rh_intr_pipe_state = OHCI_PIPE_STATE_CLOSE;
424 
425 		/* Do interrupt pipe cleanup */
426 		ohci_root_hub_intr_pipe_cleanup(ohcip, USB_CR_PIPE_CLOSING);
427 
428 		/* Set root hub interrupt pipe handle to null */
429 		ohcip->ohci_root_hub.rh_intr_pipe_handle = NULL;
430 
431 		USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
432 		    "ohci_handle_root_hub_pipe_close: "
433 		    "Root hub interrupt pipe close succeeded");
434 
435 		break;
436 	default:
437 		USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
438 		    "ohci_handle_root_hub_pipe_close: "
439 		    "Root hub pipe close failed");
440 
441 		return (USB_FAILURE);
442 	}
443 
444 	ohcip->ohci_open_pipe_count--;
445 
446 	return (USB_SUCCESS);
447 }
448 
449 
450 /*
451  * ohci_handle_root_hub_pipe_reset:
452  *
453  * Handle resetting of control and interrupt pipes on root hub.
454  */
455 /* ARGSUSED */
456 int
ohci_handle_root_hub_pipe_reset(usba_pipe_handle_data_t * ph,usb_flags_t usb_flags)457 ohci_handle_root_hub_pipe_reset(
458 	usba_pipe_handle_data_t	*ph,
459 	usb_flags_t		usb_flags)
460 {
461 	ohci_state_t		*ohcip = ohci_obtain_state(
462 	    ph->p_usba_device->usb_root_hub_dip);
463 	usb_ep_descr_t		*eptd = &ph->p_ep;
464 	int			error = USB_SUCCESS;
465 
466 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
467 	    "ohci_handle_root_hub_pipe_reset: Root hub pipe reset");
468 
469 	mutex_enter(&ohcip->ohci_int_mutex);
470 
471 	switch (eptd->bmAttributes & USB_EP_ATTR_MASK) {
472 	case USB_EP_ATTR_CONTROL:
473 		ohcip->ohci_root_hub.rh_ctrl_pipe_state = OHCI_PIPE_STATE_IDLE;
474 
475 		USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
476 		    "ohci_handle_root_hub_pipe_reset: Pipe reset"
477 		    "for the root hub control pipe successful");
478 
479 		break;
480 	case USB_EP_ATTR_INTR:
481 		ASSERT((eptd->bEndpointAddress & USB_EP_NUM_MASK) == 1);
482 
483 		if ((ohcip->ohci_root_hub.rh_client_intr_reqp) &&
484 		    (ohcip->ohci_root_hub.rh_intr_pipe_state !=
485 		    OHCI_PIPE_STATE_IDLE)) {
486 
487 			ohcip->ohci_root_hub.
488 			    rh_intr_pipe_state = OHCI_PIPE_STATE_RESET;
489 
490 			/* Do interrupt pipe cleanup */
491 			ohci_root_hub_intr_pipe_cleanup(
492 			    ohcip, USB_CR_PIPE_RESET);
493 		}
494 
495 		ASSERT(ohcip->ohci_root_hub.
496 		    rh_intr_pipe_state == OHCI_PIPE_STATE_IDLE);
497 
498 		USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
499 		    "ohci_handle_root_hub_pipe_reset: "
500 		    "Pipe reset for root hub interrupt pipe successful");
501 
502 		break;
503 	default:
504 		USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
505 		    "ohci_handle_root_hub_pipe_reset: "
506 		    "Root hub pipe reset failed");
507 
508 		error = USB_FAILURE;
509 		break;
510 	}
511 
512 	mutex_exit(&ohcip->ohci_int_mutex);
513 
514 	return (error);
515 }
516 
517 
518 /*
519  * ohci_handle_root_hub_request:
520  *
521  * Intercept a root hub request.  Handle the  root hub request through the
522  * registers
523  */
524 /* ARGSUSED */
525 int
ohci_handle_root_hub_request(ohci_state_t * ohcip,usba_pipe_handle_data_t * ph,usb_ctrl_req_t * ctrl_reqp)526 ohci_handle_root_hub_request(
527 	ohci_state_t		*ohcip,
528 	usba_pipe_handle_data_t	*ph,
529 	usb_ctrl_req_t		*ctrl_reqp)
530 {
531 	uchar_t			bmRequestType = ctrl_reqp->ctrl_bmRequestType;
532 	uchar_t			bRequest = ctrl_reqp->ctrl_bRequest;
533 	uint16_t		wValue = ctrl_reqp->ctrl_wValue;
534 	uint16_t		wIndex = ctrl_reqp->ctrl_wIndex;
535 	uint16_t		wLength = ctrl_reqp->ctrl_wLength;
536 	mblk_t			*data = ctrl_reqp->ctrl_data;
537 	uint16_t		port = wIndex - 1;  /* Adjust for controller */
538 	usb_cr_t		completion_reason;
539 	int			error = USB_SUCCESS;
540 
541 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
542 	    "ohci_handle_root_hub_request: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%p",
543 	    bmRequestType, bRequest, wValue, wIndex, wLength, (void *)data);
544 
545 	mutex_enter(&ohcip->ohci_int_mutex);
546 
547 	if (ohcip->ohci_root_hub.rh_ctrl_pipe_state != OHCI_PIPE_STATE_IDLE) {
548 
549 		USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
550 		    "ohci_handle_root_hub_request: Pipe is not idle");
551 
552 		mutex_exit(&ohcip->ohci_int_mutex);
553 
554 		return (USB_FAILURE);
555 	}
556 
557 	/* Save the current control request pointer */
558 	ohcip->ohci_root_hub.rh_curr_ctrl_reqp = ctrl_reqp;
559 
560 	/* Set pipe state to active */
561 	ohcip->ohci_root_hub.rh_ctrl_pipe_state = OHCI_PIPE_STATE_ACTIVE;
562 
563 	mutex_exit(&ohcip->ohci_int_mutex);
564 
565 	switch (bmRequestType) {
566 	case HUB_GET_DEVICE_STATUS_TYPE:
567 		ohci_handle_get_device_status(ohcip);
568 		break;
569 	case HUB_HANDLE_PORT_FEATURE_TYPE:
570 		error = ohci_handle_set_clear_port_feature(ohcip,
571 		    bRequest, wValue, port);
572 		break;
573 	case HUB_GET_PORT_STATUS_TYPE:
574 		ohci_handle_get_port_status(ohcip, port);
575 		break;
576 	case HUB_CLASS_REQ_TYPE:
577 		switch (bRequest) {
578 		case USB_REQ_GET_STATUS:
579 			ohci_handle_get_hub_status(ohcip);
580 			break;
581 		case USB_REQ_GET_DESCR:
582 			ohci_handle_get_hub_descriptor(ohcip);
583 			break;
584 		default:
585 			USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
586 			    "ohci_handle_root_hub_request:"
587 			    "Unsupported request 0x%x", bRequest);
588 
589 			error = USB_FAILURE;
590 			break;
591 		}
592 		break;
593 	case HUB_HANDLE_HUB_FEATURE_TYPE:
594 		error = ohci_handle_set_clear_hub_feature(ohcip,
595 		    bRequest, wValue);
596 		break;
597 	default:
598 		USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
599 		    "ohci_handle_root_hub_request: "
600 		    "Unsupported request 0x%x", bmRequestType);
601 
602 		error = USB_FAILURE;
603 		break;
604 	}
605 
606 	completion_reason = (error) ? USB_CR_NOT_SUPPORTED : USB_CR_OK;
607 
608 	mutex_enter(&ohcip->ohci_int_mutex);
609 	ohci_root_hub_hcdi_callback(ph, completion_reason);
610 	mutex_exit(&ohcip->ohci_int_mutex);
611 
612 	USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
613 	    "ohci_handle_root_hub_request: error = %d", error);
614 
615 	return (USB_SUCCESS);
616 }
617 
618 
619 /*
620  * ohci_handle_set_clear_port_feature:
621  */
622 static int
ohci_handle_set_clear_port_feature(ohci_state_t * ohcip,uchar_t bRequest,uint16_t wValue,uint16_t port)623 ohci_handle_set_clear_port_feature(
624 	ohci_state_t		*ohcip,
625 	uchar_t 		bRequest,
626 	uint16_t		wValue,
627 	uint16_t		port)
628 {
629 	int			error = USB_SUCCESS;
630 
631 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
632 	    "ohci_handle_set_clear_port_feature: 0x%x 0x%x 0x%x",
633 	    bRequest, wValue, port);
634 
635 	switch (bRequest) {
636 	case USB_REQ_SET_FEATURE:
637 		switch (wValue) {
638 		case CFS_PORT_ENABLE:
639 			ohci_handle_port_enable(ohcip, port, 1);
640 			break;
641 		case CFS_PORT_SUSPEND:
642 			ohci_handle_port_suspend(ohcip, port, 1);
643 			break;
644 		case CFS_PORT_RESET:
645 			ohci_handle_port_reset(ohcip, port);
646 			break;
647 		case CFS_PORT_POWER:
648 			ohci_handle_port_power(ohcip, port, 1);
649 			break;
650 		default:
651 			USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
652 			    "ohci_handle_set_clear_port_feature: "
653 			    "Unsupported request 0x%x 0x%x", bRequest, wValue);
654 
655 			error = USB_FAILURE;
656 			break;
657 		}
658 		break;
659 	case USB_REQ_CLEAR_FEATURE:
660 		switch (wValue) {
661 		case CFS_PORT_ENABLE:
662 			ohci_handle_port_enable(ohcip, port, 0);
663 			break;
664 		case CFS_C_PORT_ENABLE:
665 			ohci_handle_clrchng_port_enable(ohcip, port);
666 			break;
667 		case CFS_PORT_SUSPEND:
668 			ohci_handle_port_suspend(ohcip, port, 0);
669 			break;
670 		case CFS_C_PORT_SUSPEND:
671 			ohci_handle_clrchng_port_suspend(ohcip, port);
672 			break;
673 		case CFS_C_PORT_RESET:
674 			ohci_handle_complete_port_reset(ohcip, port);
675 			break;
676 		case CFS_PORT_POWER:
677 			ohci_handle_port_power(ohcip, port, 0);
678 			break;
679 		case CFS_C_PORT_CONNECTION:
680 			ohci_handle_clear_port_connection(ohcip, port);
681 			break;
682 		case CFS_C_PORT_OVER_CURRENT:
683 			ohci_handle_clrchng_port_over_current(ohcip, port);
684 			break;
685 		default:
686 			USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
687 			    "ohci_handle_set_clear_port_feature: "
688 			    "Unsupported request 0x%x 0x%x", bRequest, wValue);
689 
690 			error = USB_FAILURE;
691 			break;
692 		}
693 		break;
694 	default:
695 		USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
696 		    "ohci_handle_set_clear_port_feature: "
697 		    "Unsupported request 0x%x 0x%x", bRequest, wValue);
698 
699 		error = USB_FAILURE;
700 		break;
701 	}
702 
703 	return (error);
704 }
705 
706 
707 /*
708  * ohci_handle_port_power:
709  *
710  * Turn on a root hub port.
711  */
712 static void
ohci_handle_port_power(ohci_state_t * ohcip,uint16_t port,uint_t on)713 ohci_handle_port_power(
714 	ohci_state_t		*ohcip,
715 	uint16_t		port,
716 	uint_t			on)
717 {
718 	usb_hub_descr_t		*hub_descr;
719 	uint_t			port_status;
720 	ohci_root_hub_t		*rh;
721 	uint_t			p;
722 
723 	mutex_enter(&ohcip->ohci_int_mutex);
724 
725 	port_status = Get_OpReg(hcr_rh_portstatus[port]);
726 	rh = &ohcip->ohci_root_hub;
727 	hub_descr = &ohcip->ohci_root_hub.rh_descr;
728 
729 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
730 	    "ohci_handle_port_power: port = 0x%x status = 0x%x on = %d",
731 	    port, port_status, on);
732 
733 	if (on) {
734 		/*
735 		 * If the port power is ganged, enable the power through
736 		 * the status registers, else enable the port power.
737 		 */
738 		if ((hub_descr->wHubCharacteristics &
739 		    HUB_CHARS_POWER_SWITCHING_MODE) ==
740 		    HUB_CHARS_GANGED_POWER) {
741 
742 			Set_OpReg(hcr_rh_status, HCR_RH_STATUS_LPSC);
743 
744 			for (p = 0; p < hub_descr->bNbrPorts; p++) {
745 				rh->rh_port_status[p] = 0;
746 				rh->rh_port_state[p] = DISCONNECTED;
747 			}
748 		} else {
749 			/* See if the port power is already on */
750 			if (!(port_status & HCR_PORT_PPS)) {
751 				/* Turn the port on */
752 				Set_OpReg(hcr_rh_portstatus[port],
753 				    HCR_PORT_PPS);
754 			}
755 
756 			rh->rh_port_status[port] = 0;
757 			rh->rh_port_state[port] = DISCONNECTED;
758 		}
759 	} else {
760 		/*
761 		 * If the port power is ganged, disable the power through
762 		 * the status registers, else disable the port power.
763 		 */
764 		if ((hub_descr->wHubCharacteristics &
765 		    HUB_CHARS_POWER_SWITCHING_MODE) ==
766 		    HUB_CHARS_GANGED_POWER) {
767 
768 			Set_OpReg(hcr_rh_status, HCR_RH_STATUS_LPS);
769 
770 			for (p = 0; p < hub_descr->bNbrPorts; p++) {
771 				rh->rh_port_status[p] = 0;
772 				rh->rh_port_state[p] = POWERED_OFF;
773 			}
774 		} else {
775 			/* See if the port power is already OFF */
776 			if ((port_status & HCR_PORT_PPS)) {
777 				/* Turn the port OFF by writing LSSA bit  */
778 				Set_OpReg(hcr_rh_portstatus[port],
779 				    HCR_PORT_LSDA);
780 			}
781 
782 			rh->rh_port_status[port] = 0;
783 			rh->rh_port_state[port] = POWERED_OFF;
784 		}
785 	}
786 
787 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
788 	    "ohci_handle_port_power done: "
789 	    "port = 0x%x status = 0x%x on = %d",
790 	    port, Get_OpReg(hcr_rh_portstatus[port]), on);
791 
792 	mutex_exit(&ohcip->ohci_int_mutex);
793 }
794 
795 
796 /*
797  * ohci_handle_port_enable:
798  *
799  * Handle port enable request.
800  */
801 static void
ohci_handle_port_enable(ohci_state_t * ohcip,uint16_t port,uint_t on)802 ohci_handle_port_enable(
803 	ohci_state_t		*ohcip,
804 	uint16_t		port,
805 	uint_t			on)
806 {
807 	uint_t			port_status;
808 
809 	mutex_enter(&ohcip->ohci_int_mutex);
810 
811 	port_status = Get_OpReg(hcr_rh_portstatus[port]);
812 
813 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
814 	    "ohci_handle_port_enable: port = 0x%x, status = 0x%x",
815 	    port, port_status);
816 
817 	if (on) {
818 		/* See if the port enable is already on */
819 		if (!(port_status & HCR_PORT_PES)) {
820 			/* Enable the port */
821 			Set_OpReg(hcr_rh_portstatus[port], HCR_PORT_PES);
822 		}
823 	} else {
824 		/* See if the port enable is already off */
825 		if (port_status & HCR_PORT_PES) {
826 			/* disable the port by writing CCS bit */
827 			Set_OpReg(hcr_rh_portstatus[port], HCR_PORT_CCS);
828 		}
829 	}
830 
831 	mutex_exit(&ohcip->ohci_int_mutex);
832 }
833 
834 
835 /*
836  * ohci_handle_clrchng_port_enable:
837  *
838  * Handle clear port enable change bit.
839  */
840 static void
ohci_handle_clrchng_port_enable(ohci_state_t * ohcip,uint16_t port)841 ohci_handle_clrchng_port_enable(
842 	ohci_state_t		*ohcip,
843 	uint16_t		port)
844 {
845 	uint_t			port_status;
846 
847 	mutex_enter(&ohcip->ohci_int_mutex);
848 
849 	port_status = Get_OpReg(hcr_rh_portstatus[port]);
850 
851 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
852 	    "ohci_handle_port_enable: port = 0x%x, status = 0x%x",
853 	    port, port_status);
854 
855 	/* Clear the PortEnableStatusChange Bit */
856 	Set_OpReg(hcr_rh_portstatus[port], HCR_PORT_PESC);
857 
858 	mutex_exit(&ohcip->ohci_int_mutex);
859 }
860 
861 
862 /*
863  * ohci_handle_port_suspend:
864  *
865  * Handle port suspend/resume request.
866  */
867 static void
ohci_handle_port_suspend(ohci_state_t * ohcip,uint16_t port,uint_t on)868 ohci_handle_port_suspend(
869 	ohci_state_t		*ohcip,
870 	uint16_t		port,
871 	uint_t			on)
872 {
873 	uint_t			port_status;
874 
875 	mutex_enter(&ohcip->ohci_int_mutex);
876 
877 	port_status = Get_OpReg(hcr_rh_portstatus[port]);
878 
879 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
880 	    "ohci_handle_port_suspend: port = 0x%x, status = 0x%x",
881 	    port, port_status);
882 
883 	if (on) {
884 		/* Suspend the port */
885 		Set_OpReg(hcr_rh_portstatus[port], HCR_PORT_PSS);
886 	} else {
887 		/* To Resume, we write the POCI bit */
888 		Set_OpReg(hcr_rh_portstatus[port], HCR_PORT_POCI);
889 	}
890 
891 	mutex_exit(&ohcip->ohci_int_mutex);
892 }
893 
894 
895 /*
896  * ohci_handle_clrchng_port_suspend:
897  *
898  * Handle port clear port suspend change bit.
899  */
900 static void
ohci_handle_clrchng_port_suspend(ohci_state_t * ohcip,uint16_t port)901 ohci_handle_clrchng_port_suspend(
902 	ohci_state_t		*ohcip,
903 	uint16_t		port)
904 {
905 	uint_t			port_status;
906 
907 	mutex_enter(&ohcip->ohci_int_mutex);
908 
909 	port_status = Get_OpReg(hcr_rh_portstatus[port]);
910 
911 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
912 	    "ohci_handle_clrchng_port_suspend: port = 0x%x, status = 0x%x",
913 	    port, port_status);
914 
915 	Set_OpReg(hcr_rh_portstatus[port], HCR_PORT_PSSC);
916 
917 	mutex_exit(&ohcip->ohci_int_mutex);
918 }
919 
920 
921 /*
922  * ohci_handle_port_reset:
923  *
924  * Perform a port reset.
925  */
926 static void
ohci_handle_port_reset(ohci_state_t * ohcip,uint16_t port)927 ohci_handle_port_reset(
928 	ohci_state_t		*ohcip,
929 	uint16_t		port)
930 {
931 	uint_t			port_status;
932 
933 	mutex_enter(&ohcip->ohci_int_mutex);
934 
935 	port_status = Get_OpReg(hcr_rh_portstatus[port]);
936 
937 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
938 	    "ohci_handle_port_reset: port = 0x%x status = 0x%x",
939 	    port, port_status);
940 
941 	if (!(port_status & HCR_PORT_CCS)) {
942 		USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
943 		    "port_status & HCR_PORT_CCS == 0: "
944 		    "port = 0x%x status = 0x%x", port, port_status);
945 	}
946 
947 	Set_OpReg(hcr_rh_portstatus[port], HCR_PORT_PRS);
948 
949 	mutex_exit(&ohcip->ohci_int_mutex);
950 }
951 
952 
953 /*
954  * ohci_handle_complete_port_reset:
955  *
956  * Perform a port reset change.
957  */
958 static void
ohci_handle_complete_port_reset(ohci_state_t * ohcip,uint16_t port)959 ohci_handle_complete_port_reset(
960 	ohci_state_t		*ohcip,
961 	uint16_t		port)
962 {
963 	uint_t			port_status;
964 
965 	mutex_enter(&ohcip->ohci_int_mutex);
966 
967 	port_status = Get_OpReg(hcr_rh_portstatus[port]);
968 
969 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
970 	    "ohci_handle_complete_port_reset: port = 0x%x status = 0x%x",
971 	    port, port_status);
972 
973 	if (!(port_status & HCR_PORT_CCS)) {
974 		USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
975 		    "port_status & HCR_PORT_CCS == 0: "
976 		    "port = 0x%x status = 0x%x", port, port_status);
977 	}
978 
979 	Set_OpReg(hcr_rh_portstatus[port], HCR_PORT_PRSC);
980 
981 	mutex_exit(&ohcip->ohci_int_mutex);
982 }
983 
984 
985 /*
986  * ohci_handle_clear_port_connection:
987  *
988  * Perform a clear port connection.
989  */
990 static void
ohci_handle_clear_port_connection(ohci_state_t * ohcip,uint16_t port)991 ohci_handle_clear_port_connection(
992 	ohci_state_t		*ohcip,
993 	uint16_t		port)
994 {
995 	uint_t			port_status;
996 
997 	mutex_enter(&ohcip->ohci_int_mutex);
998 
999 	port_status = Get_OpReg(hcr_rh_portstatus[port]);
1000 
1001 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
1002 	    "ohci_handle_clear_port_connection: port = 0x%x"
1003 	    "status = 0x%x", port, port_status);
1004 
1005 	/* Clear CSC bit */
1006 	Set_OpReg(hcr_rh_portstatus[port], HCR_PORT_CSC);
1007 
1008 	mutex_exit(&ohcip->ohci_int_mutex);
1009 }
1010 
1011 
1012 /*
1013  * ohci_handle_clrchng_port_over_current:
1014  *
1015  * Perform a clear over current condition.
1016  */
1017 static void
ohci_handle_clrchng_port_over_current(ohci_state_t * ohcip,uint16_t port)1018 ohci_handle_clrchng_port_over_current(
1019 	ohci_state_t		*ohcip,
1020 	uint16_t		port)
1021 {
1022 	uint_t			port_status;
1023 
1024 	mutex_enter(&ohcip->ohci_int_mutex);
1025 
1026 	port_status = Get_OpReg(hcr_rh_portstatus[port]);
1027 
1028 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
1029 	    "ohci_handle_clrchng_port_over_current: port = 0x%x"
1030 	    "status = 0x%x", port, port_status);
1031 
1032 	Set_OpReg(hcr_rh_portstatus[port], HCR_PORT_OCIC);
1033 
1034 	mutex_exit(&ohcip->ohci_int_mutex);
1035 }
1036 
1037 
1038 /*
1039  * ohci_handle_get_port_status:
1040  *
1041  * Handle a get port status request.
1042  */
1043 static void
ohci_handle_get_port_status(ohci_state_t * ohcip,uint16_t port)1044 ohci_handle_get_port_status(
1045 	ohci_state_t		*ohcip,
1046 	uint16_t		port)
1047 {
1048 	usb_ctrl_req_t		*ctrl_reqp;
1049 	mblk_t			*message;
1050 	uint_t			new_port_status;
1051 	uint_t			change_status;
1052 
1053 	mutex_enter(&ohcip->ohci_int_mutex);
1054 
1055 	ctrl_reqp = ohcip->ohci_root_hub.rh_curr_ctrl_reqp;
1056 
1057 	/* Read the current port status and return it */
1058 	new_port_status = Get_OpReg(hcr_rh_portstatus[port]);
1059 	ohcip->ohci_root_hub.rh_port_status[port] = new_port_status;
1060 
1061 	change_status = (new_port_status & HCR_PORT_CHNG_MASK) >> 16;
1062 
1063 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
1064 	    "ohci_handle_get_port_status: port = %d new status = 0x%x"
1065 	    "change = 0x%x", port, new_port_status, change_status);
1066 
1067 	message = ctrl_reqp->ctrl_data;
1068 
1069 	ASSERT(message != NULL);
1070 
1071 	*message->b_wptr++ = (uchar_t)new_port_status;
1072 	*message->b_wptr++ = (uchar_t)(new_port_status >> 8);
1073 	*message->b_wptr++ = (uchar_t)change_status;
1074 	*message->b_wptr++ = (uchar_t)(change_status >> 8);
1075 
1076 	/* Save the data in control request */
1077 	ctrl_reqp->ctrl_data = message;
1078 
1079 	mutex_exit(&ohcip->ohci_int_mutex);
1080 }
1081 
1082 
1083 /*
1084  * ohci_handle_set_clear_hub_feature:
1085  *
1086  * OHCI only implements clearing C_HUB_OVER_CURRENT feature now.
1087  * Other hub requests of this bmRequestType are either not
1088  * supported by hardware or never used.
1089  */
1090 static int
ohci_handle_set_clear_hub_feature(ohci_state_t * ohcip,uchar_t bRequest,uint16_t wValue)1091 ohci_handle_set_clear_hub_feature(
1092 	ohci_state_t		*ohcip,
1093 	uchar_t 		bRequest,
1094 	uint16_t		wValue)
1095 {
1096 	int			error = USB_SUCCESS;
1097 
1098 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
1099 	    "ohci_handle_set_clear_hub_feature: 0x%x 0x%x",
1100 	    bRequest, wValue);
1101 
1102 	switch (bRequest) {
1103 	case USB_REQ_CLEAR_FEATURE:
1104 		if (wValue == CFS_C_HUB_OVER_CURRENT) {
1105 			ohci_handle_clrchng_hub_over_current(ohcip);
1106 		} else {
1107 			USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
1108 			    "ohci_handle_set_clear_hub_feature: "
1109 			    "Unsupported request 0x%x 0x%x", bRequest, wValue);
1110 
1111 			error = USB_FAILURE;
1112 		}
1113 		break;
1114 
1115 	case USB_REQ_SET_FEATURE:
1116 	default:
1117 		USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
1118 		    "ohci_handle_set_clear_hub_feature: "
1119 		    "Unsupported request 0x%x 0x%x", bRequest, wValue);
1120 
1121 		error = USB_FAILURE;
1122 		break;
1123 	}
1124 
1125 	return (error);
1126 }
1127 
1128 
1129 /*
1130  * ohci_handle_clrchng_hub_over_current:
1131  *
1132  * Clear over current indicator change bit on the root hub.
1133  */
1134 static void
ohci_handle_clrchng_hub_over_current(ohci_state_t * ohcip)1135 ohci_handle_clrchng_hub_over_current(
1136 	ohci_state_t		*ohcip)
1137 {
1138 	uint_t			hub_status;
1139 
1140 	mutex_enter(&ohcip->ohci_int_mutex);
1141 
1142 	hub_status = Get_OpReg(hcr_rh_status);
1143 
1144 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
1145 	    "ohci_handle_clrchng_hub_over_current: "
1146 	    "status = 0x%x", hub_status);
1147 
1148 	Set_OpReg(hcr_rh_status, HCR_RH_STATUS_OCIC);
1149 
1150 	mutex_exit(&ohcip->ohci_int_mutex);
1151 }
1152 
1153 
1154 /*
1155  * ohci_handle_get_hub_descriptor:
1156  */
1157 static void
ohci_handle_get_hub_descriptor(ohci_state_t * ohcip)1158 ohci_handle_get_hub_descriptor(
1159 	ohci_state_t		*ohcip)
1160 {
1161 	usb_ctrl_req_t		*ctrl_reqp;
1162 	mblk_t			*message;
1163 	usb_hub_descr_t		*root_hub_descr;
1164 	size_t			length;
1165 	uchar_t			raw_descr[ROOT_HUB_DESCRIPTOR_LENGTH];
1166 
1167 	mutex_enter(&ohcip->ohci_int_mutex);
1168 
1169 	ctrl_reqp = ohcip->ohci_root_hub.rh_curr_ctrl_reqp;
1170 	root_hub_descr = &ohcip->ohci_root_hub.rh_descr;
1171 	length = ctrl_reqp->ctrl_wLength;
1172 
1173 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
1174 	    "ohci_handle_get_hub_descriptor: Ctrl Req  = 0x%p",
1175 	    (void *)ctrl_reqp);
1176 
1177 	message = ctrl_reqp->ctrl_data;
1178 
1179 	ASSERT(message != NULL);
1180 
1181 	bzero(&raw_descr, ROOT_HUB_DESCRIPTOR_LENGTH);
1182 
1183 	raw_descr[0] = root_hub_descr->bDescLength;
1184 	raw_descr[1] = root_hub_descr->bDescriptorType;
1185 	raw_descr[2] = root_hub_descr->bNbrPorts;
1186 	raw_descr[3] = root_hub_descr->wHubCharacteristics & 0x00FF;
1187 	raw_descr[4] = (root_hub_descr->wHubCharacteristics & 0xFF00) >> 8;
1188 	raw_descr[5] = root_hub_descr->bPwrOn2PwrGood;
1189 	raw_descr[6] = root_hub_descr->bHubContrCurrent;
1190 	raw_descr[7] = root_hub_descr->DeviceRemovable;
1191 	raw_descr[8] = root_hub_descr->PortPwrCtrlMask;
1192 
1193 	bcopy(raw_descr, message->b_wptr, length);
1194 	message->b_wptr += length;
1195 
1196 	/* Save the data in control request */
1197 	ctrl_reqp->ctrl_data = message;
1198 
1199 	mutex_exit(&ohcip->ohci_int_mutex);
1200 }
1201 
1202 
1203 /*
1204  * ohci_handle_get_hub_status:
1205  *
1206  * Handle a get hub status request.
1207  */
1208 static void
ohci_handle_get_hub_status(ohci_state_t * ohcip)1209 ohci_handle_get_hub_status(
1210 	ohci_state_t		*ohcip)
1211 {
1212 	usb_ctrl_req_t		*ctrl_reqp;
1213 	mblk_t			*message;
1214 	uint_t			new_root_hub_status;
1215 
1216 	mutex_enter(&ohcip->ohci_int_mutex);
1217 
1218 	ctrl_reqp = ohcip->ohci_root_hub.rh_curr_ctrl_reqp;
1219 	new_root_hub_status = Get_OpReg(hcr_rh_status);
1220 
1221 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
1222 	    "ohci_handle_get_hub_status: new root hub status = 0x%x",
1223 	    new_root_hub_status);
1224 
1225 	message = ctrl_reqp->ctrl_data;
1226 
1227 	ASSERT(message != NULL);
1228 
1229 	*message->b_wptr++ = (uchar_t)new_root_hub_status;
1230 	*message->b_wptr++ = (uchar_t)(new_root_hub_status >> 8);
1231 	*message->b_wptr++ = (uchar_t)(new_root_hub_status >> 16);
1232 	*message->b_wptr++ = (uchar_t)(new_root_hub_status >> 24);
1233 
1234 	/* Save the data in control request */
1235 	ctrl_reqp->ctrl_data = message;
1236 
1237 	mutex_exit(&ohcip->ohci_int_mutex);
1238 }
1239 
1240 
1241 /*
1242  * ohci_handle_get_device_status:
1243  *
1244  * Handle a get device status request.
1245  */
1246 static void
ohci_handle_get_device_status(ohci_state_t * ohcip)1247 ohci_handle_get_device_status(
1248 	ohci_state_t		*ohcip)
1249 {
1250 	usb_ctrl_req_t		*ctrl_reqp;
1251 	mblk_t			*message;
1252 	uint16_t		dev_status;
1253 
1254 	mutex_enter(&ohcip->ohci_int_mutex);
1255 
1256 	ctrl_reqp = ohcip->ohci_root_hub.rh_curr_ctrl_reqp;
1257 
1258 	/*
1259 	 * OHCI doesn't have device status information.
1260 	 * Simply return what is desired for the request.
1261 	 */
1262 	dev_status = USB_DEV_SLF_PWRD_STATUS;
1263 
1264 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
1265 	    "ohci_handle_get_device_status: device status = 0x%x",
1266 	    dev_status);
1267 
1268 	message = ctrl_reqp->ctrl_data;
1269 
1270 	ASSERT(message != NULL);
1271 
1272 	*message->b_wptr++ = (uchar_t)dev_status;
1273 	*message->b_wptr++ = (uchar_t)(dev_status >> 8);
1274 
1275 	/* Save the data in control request */
1276 	ctrl_reqp->ctrl_data = message;
1277 
1278 	mutex_exit(&ohcip->ohci_int_mutex);
1279 }
1280 
1281 
1282 /*
1283  * ohci_handle_root_hub_pipe_start_intr_polling:
1284  *
1285  * Handle start polling on root hub interrupt pipe.
1286  */
1287 /* ARGSUSED */
1288 int
ohci_handle_root_hub_pipe_start_intr_polling(usba_pipe_handle_data_t * ph,usb_intr_req_t * client_intr_reqp,usb_flags_t flags)1289 ohci_handle_root_hub_pipe_start_intr_polling(
1290 	usba_pipe_handle_data_t	*ph,
1291 	usb_intr_req_t		*client_intr_reqp,
1292 	usb_flags_t		flags)
1293 {
1294 	ohci_state_t		*ohcip = ohci_obtain_state(
1295 	    ph->p_usba_device->usb_root_hub_dip);
1296 	usb_ep_descr_t		*eptd = &ph->p_ep;
1297 	int			error = USB_SUCCESS;
1298 	uint_t			pipe_state;
1299 
1300 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
1301 	    "ohci_handle_root_hub_pipe_start_intr_polling: "
1302 	    "Root hub pipe start polling");
1303 
1304 	ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
1305 
1306 	ASSERT((eptd->bEndpointAddress & USB_EP_NUM_MASK) == 1);
1307 
1308 	/* ONE_XFER not supported for root hub interrupt pipe */
1309 	ASSERT((client_intr_reqp->intr_attributes & USB_ATTRS_ONE_XFER) == 0);
1310 
1311 	/* Get root hub intr pipe state */
1312 	pipe_state = ohcip->ohci_root_hub.rh_intr_pipe_state;
1313 
1314 	switch (pipe_state) {
1315 	case OHCI_PIPE_STATE_IDLE:
1316 		ASSERT(ohcip->ohci_root_hub.rh_intr_pipe_timer_id == 0);
1317 
1318 		/*
1319 		 * Save the Original Client's Interrupt IN request
1320 		 * information. We use this for final callback
1321 		 */
1322 		ASSERT(ohcip->ohci_root_hub.rh_client_intr_reqp == NULL);
1323 
1324 		ohcip->ohci_root_hub.rh_client_intr_reqp = client_intr_reqp;
1325 
1326 		error = ohci_root_hub_allocate_intr_pipe_resource(ohcip, flags);
1327 
1328 		if (error != USB_SUCCESS) {
1329 			/* Reset client interrupt request pointer */
1330 			ohcip->ohci_root_hub.rh_client_intr_reqp = NULL;
1331 
1332 			USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
1333 			    "ohci_handle_root_hub_pipe_start_intr_polling: "
1334 			    "No Resources");
1335 
1336 			return (error);
1337 		}
1338 
1339 		USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
1340 		    "ohci_handle_root_hub_pipe_start_intr_polling: "
1341 		    "Start polling for root hub successful");
1342 
1343 		break;
1344 	case OHCI_PIPE_STATE_ACTIVE:
1345 		USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
1346 		    "ohci_handle_root_hub_pipe_start_intr_polling: "
1347 		    "Polling for root hub is already in progress");
1348 
1349 		break;
1350 	default:
1351 		USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
1352 		    "ohci_handle_root_hub_pipe_start_intr_polling: "
1353 		    "Pipe is in error state 0x%x", pipe_state);
1354 
1355 		error = USB_FAILURE;
1356 
1357 		break;
1358 	}
1359 
1360 	return (error);
1361 }
1362 
1363 
1364 /*
1365  * ohci_handle_root_hub_pipe_stop_intr_polling:
1366  *
1367  * Handle stop polling on root hub intr pipe.
1368  */
1369 /* ARGSUSED */
1370 void
ohci_handle_root_hub_pipe_stop_intr_polling(usba_pipe_handle_data_t * ph,usb_flags_t flags)1371 ohci_handle_root_hub_pipe_stop_intr_polling(
1372 	usba_pipe_handle_data_t	*ph,
1373 	usb_flags_t		flags)
1374 {
1375 	ohci_state_t		*ohcip = ohci_obtain_state(
1376 	    ph->p_usba_device->usb_root_hub_dip);
1377 	usb_ep_descr_t		*eptd = &ph->p_ep;
1378 
1379 	ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
1380 
1381 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
1382 	    "ohci_handle_root_hub_pipe_stop_intr_polling: "
1383 	    "Root hub pipe stop polling");
1384 
1385 	ASSERT((eptd->bEndpointAddress & USB_EP_NUM_MASK) == 1);
1386 
1387 	if (ohcip->ohci_root_hub.rh_intr_pipe_state == OHCI_PIPE_STATE_ACTIVE) {
1388 
1389 		ohcip->ohci_root_hub.rh_intr_pipe_state =
1390 		    OHCI_PIPE_STATE_STOP_POLLING;
1391 
1392 		/* Do interrupt pipe cleanup */
1393 		ohci_root_hub_intr_pipe_cleanup(ohcip, USB_CR_STOPPED_POLLING);
1394 
1395 		ASSERT(ohcip->ohci_root_hub.
1396 		    rh_intr_pipe_state == OHCI_PIPE_STATE_IDLE);
1397 
1398 		USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
1399 		    "ohci_hcdi_pipe_stop_intr_polling: Stop polling for root"
1400 		    "hub successful");
1401 	} else {
1402 		USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
1403 		    "ohci_hcdi_pipe_stop_intr_polling: "
1404 		    "Polling for root hub is already stopped");
1405 	}
1406 }
1407 
1408 
1409 /*
1410  * ohci_root_hub_allocate_intr_pipe_resource:
1411  *
1412  * Allocate interrupt requests and initialize them.
1413  */
1414 static int
ohci_root_hub_allocate_intr_pipe_resource(ohci_state_t * ohcip,usb_flags_t flags)1415 ohci_root_hub_allocate_intr_pipe_resource(
1416 	ohci_state_t		*ohcip,
1417 	usb_flags_t		flags)
1418 {
1419 	usba_pipe_handle_data_t	*ph;
1420 	size_t			length;
1421 	usb_intr_req_t		*curr_intr_reqp;
1422 
1423 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
1424 	    "ohci_root_hub_allocate_intr_pipe_resource");
1425 
1426 	ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
1427 
1428 	/* Get the interrupt pipe handle */
1429 	ph = ohcip->ohci_root_hub.rh_intr_pipe_handle;
1430 
1431 	/* Get the current interrupt request pointer */
1432 	curr_intr_reqp = ohcip->ohci_root_hub.rh_curr_intr_reqp;
1433 
1434 	/*
1435 	 * If current interrupt request pointer is null,
1436 	 * allocate new interrupt request.
1437 	 */
1438 	if (curr_intr_reqp == NULL) {
1439 		ASSERT(ohcip->ohci_root_hub.rh_client_intr_reqp);
1440 
1441 		/* Get the length of interrupt transfer */
1442 		length = ohcip->ohci_root_hub.
1443 		    rh_client_intr_reqp->intr_len;
1444 
1445 		curr_intr_reqp = usba_hcdi_dup_intr_req(ph->p_dip,
1446 		    ohcip->ohci_root_hub.rh_client_intr_reqp,
1447 		    length, flags);
1448 
1449 		if (curr_intr_reqp == NULL) {
1450 
1451 			USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
1452 			    "ohci_root_hub_allocate_intr_pipe_resource:"
1453 			    "Interrupt request structure allocation failed");
1454 
1455 			return (USB_NO_RESOURCES);
1456 		}
1457 
1458 		ohcip->ohci_root_hub.rh_curr_intr_reqp = curr_intr_reqp;
1459 
1460 		mutex_enter(&ph->p_mutex);
1461 		ph->p_req_count++;
1462 		mutex_exit(&ph->p_mutex);
1463 	}
1464 
1465 	/* Start the timer for the root hub interrupt pipe polling */
1466 	if (ohcip->ohci_root_hub.rh_intr_pipe_timer_id == 0) {
1467 		ohcip->ohci_root_hub.rh_intr_pipe_timer_id =
1468 		    timeout(ohci_handle_root_hub_status_change,
1469 		    (void *)ohcip, drv_usectohz(OHCI_RH_POLL_TIME));
1470 
1471 		ohcip->ohci_root_hub.
1472 		    rh_intr_pipe_state = OHCI_PIPE_STATE_ACTIVE;
1473 	}
1474 
1475 	return (USB_SUCCESS);
1476 }
1477 
1478 
1479 /*
1480  * ohci_root_hub_intr_pipe_cleanup:
1481  *
1482  * Deallocate all interrupt requests and do callback
1483  * the original client interrupt request.
1484  */
1485 static void
ohci_root_hub_intr_pipe_cleanup(ohci_state_t * ohcip,usb_cr_t completion_reason)1486 ohci_root_hub_intr_pipe_cleanup(
1487 	ohci_state_t		*ohcip,
1488 	usb_cr_t		completion_reason)
1489 {
1490 	usb_intr_req_t		*curr_intr_reqp;
1491 	usb_opaque_t		client_intr_reqp;
1492 	timeout_id_t		timer_id;
1493 	usba_pipe_handle_data_t	*ph;
1494 
1495 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
1496 	    "ohci_root_hub_intr_pipe_cleanup");
1497 
1498 	ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
1499 
1500 	/* Get the interrupt pipe handle */
1501 	ph = ohcip->ohci_root_hub.rh_intr_pipe_handle;
1502 
1503 	/* Get the interrupt timerid */
1504 	timer_id = ohcip->ohci_root_hub.rh_intr_pipe_timer_id;
1505 
1506 	/* Stop the root hub interrupt timer */
1507 	if (timer_id) {
1508 		/* Reset the timer id to zero */
1509 		ohcip->ohci_root_hub.rh_intr_pipe_timer_id = 0;
1510 
1511 		mutex_exit(&ohcip->ohci_int_mutex);
1512 		(void) untimeout(timer_id);
1513 		mutex_enter(&ohcip->ohci_int_mutex);
1514 	}
1515 
1516 	/* Reset the current interrupt request pointer */
1517 	curr_intr_reqp = ohcip->ohci_root_hub.rh_curr_intr_reqp;
1518 
1519 	/* Deallocate uncompleted interrupt request */
1520 	if (curr_intr_reqp) {
1521 		ohcip->ohci_root_hub.rh_curr_intr_reqp = NULL;
1522 		usb_free_intr_req(curr_intr_reqp);
1523 
1524 		mutex_enter(&ph->p_mutex);
1525 		ph->p_req_count--;
1526 		mutex_exit(&ph->p_mutex);
1527 	}
1528 
1529 	client_intr_reqp = (usb_opaque_t)
1530 	    ohcip->ohci_root_hub.rh_client_intr_reqp;
1531 
1532 	/* Callback for original client interrupt request */
1533 	if (client_intr_reqp) {
1534 		ohci_root_hub_hcdi_callback(ph, completion_reason);
1535 	}
1536 }
1537 
1538 
1539 /*
1540  * ohci_handle_root_hub_status_change:
1541  *
1542  * A root hub status change interrupt will occur any time there is a change
1543  * in the root hub status register or one of the port status registers.
1544  */
1545 void
ohci_handle_root_hub_status_change(void * arg)1546 ohci_handle_root_hub_status_change(void *arg)
1547 {
1548 	ohci_state_t		*ohcip = (ohci_state_t *)arg;
1549 	usb_intr_req_t		*curr_intr_reqp;
1550 	usb_port_mask_t		all_ports_status = 0;
1551 	uint_t			new_root_hub_status;
1552 	uint_t			new_port_status;
1553 	uint_t			change_status;
1554 	usb_hub_descr_t		*hub_descr;
1555 	mblk_t			*message;
1556 	size_t			length;
1557 	usb_ep_descr_t		*eptd;
1558 	usba_pipe_handle_data_t	*ph;
1559 	int			i;
1560 
1561 	mutex_enter(&ohcip->ohci_int_mutex);
1562 
1563 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
1564 	    "ohci_handle_root_hub_status_change: state = %d",
1565 	    ohcip->ohci_root_hub.rh_intr_pipe_state);
1566 
1567 	/* Get the pointer to root hub descriptor */
1568 	hub_descr = &ohcip->ohci_root_hub.rh_descr;
1569 
1570 	/* Get the current interrupt request pointer */
1571 	curr_intr_reqp = ohcip->ohci_root_hub.rh_curr_intr_reqp;
1572 
1573 	ph = ohcip->ohci_root_hub.rh_intr_pipe_handle;
1574 
1575 	/* Check whether timeout handler is valid */
1576 	if (ohcip->ohci_root_hub.rh_intr_pipe_timer_id) {
1577 		/* Check host controller is in operational state */
1578 		if ((ohci_state_is_operational(ohcip)) != USB_SUCCESS) {
1579 
1580 			/* Reset the timer id */
1581 			ohcip->ohci_root_hub.rh_intr_pipe_timer_id = 0;
1582 
1583 			/* Do interrupt pipe cleanup */
1584 			ohci_root_hub_intr_pipe_cleanup(
1585 			    ohcip, USB_CR_HC_HARDWARE_ERR);
1586 
1587 			mutex_exit(&ohcip->ohci_int_mutex);
1588 
1589 			return;
1590 		}
1591 	} else {
1592 		mutex_exit(&ohcip->ohci_int_mutex);
1593 
1594 		return;
1595 	}
1596 
1597 	eptd = &ohcip->ohci_root_hub.rh_intr_pipe_handle->p_ep;
1598 
1599 	new_root_hub_status = Get_OpReg(hcr_rh_status);
1600 
1601 	/* See if the root hub status has changed */
1602 	if (new_root_hub_status & HCR_RH_CHNG_MASK) {
1603 
1604 		USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
1605 		    "ohci_handle_root_hub_status_change: "
1606 		    "Root hub status has changed!");
1607 
1608 		all_ports_status = 1;
1609 
1610 		/* Update root hub status */
1611 		ohcip->ohci_root_hub.rh_status = new_root_hub_status;
1612 	}
1613 
1614 	/* Check each port */
1615 	for (i = 0; i < hub_descr->bNbrPorts; i++) {
1616 		new_port_status = Get_OpReg(hcr_rh_portstatus[i]);
1617 		change_status = new_port_status & HCR_PORT_CHNG_MASK;
1618 
1619 		/*
1620 		 * If there is change in the port status then set
1621 		 * the bit in the bitmap of changes and inform hub
1622 		 * driver about these changes. Hub driver will take
1623 		 * care of these changes.
1624 		 */
1625 		if (change_status) {
1626 
1627 			/* See if a device was attached/detached */
1628 			if (change_status & HCR_PORT_CSC) {
1629 				/*
1630 				 * Update the state depending on whether
1631 				 * the port was attached or detached.
1632 				 */
1633 				if (new_port_status & HCR_PORT_CCS) {
1634 					ohcip->ohci_root_hub.
1635 					    rh_port_state[i] = DISABLED;
1636 
1637 					USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB,
1638 					    ohcip->ohci_log_hdl,
1639 					    "Port %d connected", i+1);
1640 				} else {
1641 					ohcip->ohci_root_hub.
1642 					    rh_port_state[i] = DISCONNECTED;
1643 
1644 					USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB,
1645 					    ohcip->ohci_log_hdl,
1646 					    "Port %d disconnected", i+1);
1647 				}
1648 			}
1649 
1650 			/* See if port enable status changed */
1651 			if (change_status & HCR_PORT_PESC) {
1652 				/*
1653 				 * Update the state depending on whether
1654 				 * the port was enabled or disabled.
1655 				 */
1656 				if (new_port_status & HCR_PORT_PES) {
1657 					ohcip->ohci_root_hub.
1658 					    rh_port_state[i] = ENABLED;
1659 
1660 					USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB,
1661 					    ohcip->ohci_log_hdl,
1662 					    "Port %d enabled", i+1);
1663 				} else {
1664 					ohcip->ohci_root_hub.
1665 					    rh_port_state[i] = DISABLED;
1666 
1667 					USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB,
1668 					    ohcip->ohci_log_hdl,
1669 					    "Port %d disabled", i+1);
1670 				}
1671 			}
1672 
1673 			all_ports_status |= 1 << (i + 1);
1674 
1675 			/* Update the status */
1676 			ohcip->ohci_root_hub.
1677 			    rh_port_status[i] = new_port_status;
1678 		}
1679 	}
1680 
1681 	if (ph && all_ports_status && curr_intr_reqp) {
1682 
1683 		length = eptd->wMaxPacketSize;
1684 
1685 		ASSERT(length != 0);
1686 
1687 		/* Get the  message block */
1688 		message = curr_intr_reqp->intr_data;
1689 
1690 		ASSERT(message != NULL);
1691 
1692 		do {
1693 			/*
1694 			 * check that mblk is big enough when we
1695 			 * are writing bytes into it
1696 			 */
1697 			if (message->b_wptr >= message->b_datap->db_lim) {
1698 
1699 				USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB,
1700 				    ohcip->ohci_log_hdl,
1701 				    "ohci_handle_root_hub_status_change: "
1702 				    "mblk data overflow.");
1703 
1704 				break;
1705 			}
1706 
1707 			*message->b_wptr++ = (uchar_t)all_ports_status;
1708 			all_ports_status >>= 8;
1709 		} while (all_ports_status != 0);
1710 
1711 		ohci_root_hub_hcdi_callback(ph, USB_CR_OK);
1712 	}
1713 
1714 	/* Reset the timer id */
1715 	ohcip->ohci_root_hub.rh_intr_pipe_timer_id = 0;
1716 
1717 	if (ohcip->ohci_root_hub.rh_intr_pipe_state == OHCI_PIPE_STATE_ACTIVE) {
1718 		/*
1719 		 * If needed, allocate new interrupt request. Also
1720 		 * start the timer for the root hub interrupt polling.
1721 		 */
1722 		if ((ohci_root_hub_allocate_intr_pipe_resource(
1723 		    ohcip, 0)) != USB_SUCCESS) {
1724 
1725 			USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
1726 			    "ohci_handle_root_hub_status_change: No Resources");
1727 
1728 			/* Do interrupt pipe cleanup */
1729 			ohci_root_hub_intr_pipe_cleanup(
1730 			    ohcip, USB_CR_NO_RESOURCES);
1731 		}
1732 	}
1733 
1734 	mutex_exit(&ohcip->ohci_int_mutex);
1735 }
1736 
1737 
1738 /*
1739  * ohci_root_hub_hcdi_callback()
1740  *
1741  * Convenience wrapper around usba_hcdi_cb() for the root hub.
1742  */
1743 static void
ohci_root_hub_hcdi_callback(usba_pipe_handle_data_t * ph,usb_cr_t completion_reason)1744 ohci_root_hub_hcdi_callback(
1745 	usba_pipe_handle_data_t	*ph,
1746 	usb_cr_t		completion_reason)
1747 {
1748 	ohci_state_t		*ohcip = ohci_obtain_state(
1749 	    ph->p_usba_device->usb_root_hub_dip);
1750 	uchar_t			attributes = ph->p_ep.bmAttributes &
1751 	    USB_EP_ATTR_MASK;
1752 	usb_opaque_t		curr_xfer_reqp;
1753 	uint_t			pipe_state = 0;
1754 
1755 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ohcip->ohci_log_hdl,
1756 	    "ohci_root_hub_hcdi_callback: ph = 0x%p, cr = 0x%x",
1757 	    (void *)ph, completion_reason);
1758 
1759 	ASSERT(mutex_owned(&ohcip->ohci_int_mutex));
1760 
1761 	/* Set the pipe state as per completion reason */
1762 	switch (completion_reason) {
1763 	case USB_CR_OK:
1764 		switch (attributes) {
1765 		case USB_EP_ATTR_CONTROL:
1766 			pipe_state = OHCI_PIPE_STATE_IDLE;
1767 			break;
1768 		case USB_EP_ATTR_INTR:
1769 			pipe_state = ohcip->ohci_root_hub.rh_intr_pipe_state;
1770 			break;
1771 		}
1772 		break;
1773 	case USB_CR_NO_RESOURCES:
1774 	case USB_CR_NOT_SUPPORTED:
1775 	case USB_CR_STOPPED_POLLING:
1776 	case USB_CR_PIPE_RESET:
1777 	case USB_CR_HC_HARDWARE_ERR:
1778 		/* Set pipe state to idle */
1779 		pipe_state = OHCI_PIPE_STATE_IDLE;
1780 		break;
1781 	case USB_CR_PIPE_CLOSING:
1782 		break;
1783 	default:
1784 		/* Set pipe state to error */
1785 		pipe_state = OHCI_PIPE_STATE_ERROR;
1786 		break;
1787 	}
1788 
1789 	switch (attributes) {
1790 	case USB_EP_ATTR_CONTROL:
1791 		curr_xfer_reqp = (usb_opaque_t)
1792 		    ohcip->ohci_root_hub.rh_curr_ctrl_reqp;
1793 
1794 		ohcip->ohci_root_hub.rh_curr_ctrl_reqp = NULL;
1795 		ohcip->ohci_root_hub.rh_ctrl_pipe_state = pipe_state;
1796 		break;
1797 	case USB_EP_ATTR_INTR:
1798 		/* if curr_intr_reqp available then use this request */
1799 		if (ohcip->ohci_root_hub.rh_curr_intr_reqp) {
1800 			curr_xfer_reqp = (usb_opaque_t)
1801 			    ohcip->ohci_root_hub.rh_curr_intr_reqp;
1802 
1803 			ohcip->ohci_root_hub.rh_curr_intr_reqp = NULL;
1804 		} else {
1805 			/* no current request, use client's request */
1806 			curr_xfer_reqp = (usb_opaque_t)
1807 			    ohcip->ohci_root_hub.rh_client_intr_reqp;
1808 
1809 			ohcip->ohci_root_hub.rh_client_intr_reqp = NULL;
1810 		}
1811 
1812 		ohcip->ohci_root_hub.rh_intr_pipe_state = pipe_state;
1813 		break;
1814 	}
1815 
1816 	ASSERT(curr_xfer_reqp != NULL);
1817 
1818 	mutex_exit(&ohcip->ohci_int_mutex);
1819 	usba_hcdi_cb(ph, curr_xfer_reqp, completion_reason);
1820 	mutex_enter(&ohcip->ohci_int_mutex);
1821 }
1822