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