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