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