xref: /titanic_50/usr/src/uts/common/io/usb/hcd/ehci/ehci_hub.c (revision 6a634c9dca3093f3922e4b7ab826d7bdf17bf78e)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
23  */
24 
25 /*
26  * EHCI Host Controller Driver (EHCI)
27  *
28  * The EHCI driver is a software driver which interfaces to the Universal
29  * Serial Bus layer (USBA) and the Host Controller (HC). The interface to
30  * the Host Controller is defined by the EHCI Host Controller Interface.
31  *
32  * This module contains the code for root hub related functions.
33  *
34  * NOTE:
35  *
36  * ONE_XFER is not supported on root hub interrupt polling
37  */
38 
39 #include <sys/usb/hcd/ehci/ehcid.h>
40 #include <sys/usb/hcd/ehci/ehci_util.h>
41 #include <sys/usb/usba/usba_types.h>
42 
43 /* Static function prototypes */
44 static int	ehci_handle_set_clear_port_feature(
45 				ehci_state_t		*ehcip,
46 				uchar_t 		bRequest,
47 				uint16_t		wValue,
48 				uint16_t		port);
49 static void	ehci_handle_port_power(
50 				ehci_state_t		*ehcip,
51 				uint16_t		port,
52 				uint_t			on);
53 static void	ehci_handle_port_enable(
54 				ehci_state_t		*ehcip,
55 				uint16_t		port,
56 				uint_t			on);
57 static void	ehci_handle_clrchng_port_enable(
58 				ehci_state_t		*ehcip,
59 				uint16_t		port);
60 static void	ehci_handle_port_suspend(
61 				ehci_state_t		*ehcip,
62 				uint16_t		port,
63 				uint_t			on);
64 static void	ehci_handle_clrchng_port_suspend(
65 				ehci_state_t		*ehcip,
66 				uint16_t		port);
67 static void	ehci_handle_port_reset(
68 				ehci_state_t		*ehcip,
69 				uint16_t		port);
70 static void	ehci_root_hub_reset_occured(
71 				ehci_state_t		*ehcip);
72 static void	ehci_handle_complete_port_reset(
73 				ehci_state_t		*ehcip,
74 				uint16_t		port);
75 static void	ehci_handle_clear_port_connection(
76 				ehci_state_t		*ehcip,
77 				uint16_t		port);
78 static void	ehci_handle_clrchng_port_over_current(
79 				ehci_state_t		*ehcip,
80 				uint16_t		port);
81 static void	ehci_handle_get_port_status(
82 				ehci_state_t		*ehcip,
83 				uint16_t		port);
84 static void	ehci_handle_get_hub_descriptor(
85 				ehci_state_t		*ehcip);
86 static void	ehci_handle_get_hub_status(
87 				ehci_state_t		*ehcip);
88 static void	ehci_handle_get_device_status(
89 				ehci_state_t		*ehcip);
90 static uint_t	ehci_get_root_hub_port_status(
91 				ehci_state_t		*ehcip,
92 				uint16_t		port);
93 static int	ehci_is_port_owner(
94 				ehci_state_t		*ehcip,
95 				uint16_t		port);
96 static int	ehci_root_hub_allocate_intr_pipe_resource(
97 				ehci_state_t		*ehcip,
98 				usb_flags_t		flags);
99 static void	ehci_root_hub_intr_pipe_cleanup(
100 				ehci_state_t		*ehcip,
101 				usb_cr_t		completion_reason);
102 static void	ehci_handle_root_hub_status_change(void *arg);
103 static void	ehci_root_hub_hcdi_callback(
104 				usba_pipe_handle_data_t	*ph,
105 				usb_cr_t		completion_reason);
106 
107 
108 /*
109  * ehci_init_root_hub:
110  *
111  * Initialize the root hub
112  */
113 int
ehci_init_root_hub(ehci_state_t * ehcip)114 ehci_init_root_hub(ehci_state_t	*ehcip)
115 {
116 	usb_hub_descr_t		*root_hub_descr =
117 	    &ehcip->ehci_root_hub.rh_descr;
118 	uint_t			i, length, port_state;
119 	uint32_t		capability;
120 
121 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
122 	    "ehci_init_root_hub:");
123 
124 	/* Read the EHCI capability register */
125 	capability = Get_Cap(ehci_hcs_params);
126 
127 	/*
128 	 * Build the Root hub descriptor by looking EHCI capability
129 	 * and operational registers.
130 	 */
131 	root_hub_descr->bDescriptorType = ROOT_HUB_DESCRIPTOR_TYPE;
132 
133 	if ((capability & EHCI_HCS_NUM_PORTS) > EHCI_MAX_RH_PORTS) {
134 
135 		USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
136 		    "ehci_init_root_hub: Invalid no of root hub ports 0x%x",
137 		    capability & EHCI_HCS_NUM_PORTS);
138 
139 		return (USB_FAILURE);
140 	}
141 
142 	/* Obtain the number of downstream ports */
143 	root_hub_descr->bNbrPorts = capability & EHCI_HCS_NUM_PORTS;
144 
145 	length = root_hub_descr->bNbrPorts / 8;
146 
147 	if (length) {
148 		root_hub_descr->bDescLength = 7 + (2 * (length + 1));
149 	} else {
150 		root_hub_descr->bDescLength = ROOT_HUB_DESCRIPTOR_LENGTH;
151 	}
152 
153 	/*
154 	 * Obtain the number of Classic or Companion USB 1.1 (OHCI/UHCI)
155 	 * Host Controllers information.
156 	 */
157 	ehcip->ehci_root_hub.rh_companion_controllers = (capability &
158 	    EHCI_HCS_NUM_COMP_CTRLS) >> EHCI_HCS_NUM_COMP_CTRL_SHIFT;
159 
160 	/*
161 	 * Determine the Power Switching Mode
162 	 *
163 	 * EHCI Specification, root hub supports either no power switching
164 	 * individual port power switching. Also determine the Over-current
165 	 * Protection Mode.
166 	 */
167 	if (capability & EHCI_HCS_PORT_POWER_CONTROL) {
168 		/* Each port is powered individually */
169 		root_hub_descr-> wHubCharacteristics =
170 		    HUB_CHARS_INDIVIDUAL_PORT_POWER;
171 
172 		/* Assume individual overcurrent reporting */
173 		root_hub_descr->wHubCharacteristics |=
174 		    HUB_CHARS_INDIV_OVER_CURRENT;
175 
176 		/* Each port will start off in the POWERED_OFF mode */
177 		port_state = POWERED_OFF;
178 	} else {
179 		/* The ports are powered when the ctlr is powered */
180 		root_hub_descr->
181 		    wHubCharacteristics = HUB_CHARS_NO_POWER_SWITCHING;
182 
183 		/* Assume no overcurrent reporting */
184 		root_hub_descr->wHubCharacteristics |=
185 		    HUB_CHARS_NO_OVER_CURRENT;
186 
187 		port_state = DISCONNECTED;
188 	}
189 
190 	/* Look at the port indicator information */
191 	if (capability & EHCI_HCS_PORT_INDICATOR) {
192 		root_hub_descr->wHubCharacteristics |= HUB_CHARS_PORT_INDICATOR;
193 	}
194 
195 	/*
196 	 * Obtain the power on to power good time of the ports.
197 	 *
198 	 * Assume: Zero for this field.
199 	 */
200 	root_hub_descr->bPwrOn2PwrGood = 2;
201 
202 	USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
203 	    "Power on to power good %d", root_hub_descr->bPwrOn2PwrGood);
204 
205 	/* Indicate if the device is removable */
206 	root_hub_descr->DeviceRemovable = 0;
207 
208 	/* Set PortPowerControlMask to zero */
209 	root_hub_descr->PortPwrCtrlMask = 0;
210 
211 	/* Set the state of each port and initialize the status */
212 	for (i = 0; i < root_hub_descr->bNbrPorts; i++) {
213 
214 		/* Initilize state/status of each root hub port */
215 		ehcip->ehci_root_hub.rh_port_state[i] = port_state;
216 		ehcip->ehci_root_hub.rh_port_status[i] = 0;
217 	}
218 
219 	return (USB_SUCCESS);
220 }
221 
222 
223 /*
224  * ehci_load_root_hub_driver:
225  *
226  * Attach the root hub
227  */
228 static usb_dev_descr_t ehci_root_hub_device_descriptor = {
229 	0x12,		/* bLength */
230 	0x01,		/* bDescriptorType, Device */
231 	0x200,		/* bcdUSB, v2.0 */
232 	0x09,		/* bDeviceClass */
233 	0x00,		/* bDeviceSubClass */
234 	0x01,		/* bDeviceProtocol */
235 	0x40,		/* bMaxPacketSize0 */
236 	0x00,		/* idVendor */
237 	0x00,		/* idProduct */
238 	0x00,		/* bcdDevice */
239 	0x00,		/* iManufacturer */
240 	0x00,		/* iProduct */
241 	0x00,		/* iSerialNumber */
242 	0x01		/* bNumConfigurations */
243 };
244 
245 static uchar_t ehci_root_hub_config_descriptor[] = {
246 	/* One configuartion */
247 	0x09,		/* bLength */
248 	0x02,		/* bDescriptorType, Configuartion */
249 	0x19, 0x00,	/* wTotalLength */
250 	0x01,		/* bNumInterfaces */
251 	0x01,		/* bConfigurationValue */
252 	0x00,		/* iConfiguration */
253 	0x40,		/* bmAttributes */
254 	0x00,		/* MaxPower */
255 
256 	/* One Interface */
257 	0x09,		/* bLength */
258 	0x04,		/* bDescriptorType, Interface */
259 	0x00,		/* bInterfaceNumber */
260 	0x00,		/* bAlternateSetting */
261 	0x01,		/* bNumEndpoints */
262 	0x09,		/* bInterfaceClass */
263 	0x01,		/* bInterfaceSubClass */
264 	0x00,		/* bInterfaceProtocol */
265 	0x00,		/* iInterface */
266 
267 	/* One Endpoint (status change endpoint) */
268 	0x07,		/* bLength */
269 	0x05,		/* bDescriptorType, Endpoint */
270 	0x81,		/* bEndpointAddress */
271 	0x03,		/* bmAttributes */
272 	0x01, 0x00,	/* wMaxPacketSize, 1 +	(EHCI_MAX_RH_PORTS / 8) */
273 	0xff		/* bInterval */
274 };
275 
276 int
ehci_load_root_hub_driver(ehci_state_t * ehcip)277 ehci_load_root_hub_driver(ehci_state_t	*ehcip)
278 {
279 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
280 	    "ehci_load_root_hub_driver:");
281 
282 	return (usba_hubdi_bind_root_hub(ehcip->ehci_dip,
283 	    ehci_root_hub_config_descriptor,
284 	    sizeof (ehci_root_hub_config_descriptor),
285 	    &ehci_root_hub_device_descriptor));
286 }
287 
288 
289 /*
290  * ehci_unload_root_hub_driver:
291  */
292 int
ehci_unload_root_hub_driver(ehci_state_t * ehcip)293 ehci_unload_root_hub_driver(ehci_state_t	*ehcip)
294 {
295 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
296 	    "ehci_unload_root_hub_driver:");
297 
298 	return (usba_hubdi_unbind_root_hub(ehcip->ehci_dip));
299 }
300 
301 
302 /*
303  * ehci_handle_root_hub_pipe_open:
304  *
305  * Handle opening of control and interrupt pipes on root hub.
306  */
307 /* ARGSUSED */
308 int
ehci_handle_root_hub_pipe_open(usba_pipe_handle_data_t * ph,usb_flags_t usb_flags)309 ehci_handle_root_hub_pipe_open(
310 	usba_pipe_handle_data_t	*ph,
311 	usb_flags_t		usb_flags)
312 {
313 	ehci_state_t		*ehcip = ehci_obtain_state(
314 	    ph->p_usba_device->usb_root_hub_dip);
315 	usb_ep_descr_t		*eptd = &ph->p_ep;
316 
317 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
318 	    "ehci_handle_root_hub_pipe_open: Root hub pipe open");
319 
320 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
321 
322 	switch (eptd->bmAttributes & USB_EP_ATTR_MASK) {
323 	case USB_EP_ATTR_CONTROL:
324 		/* Save control pipe handle */
325 		ehcip->ehci_root_hub.rh_ctrl_pipe_handle = ph;
326 
327 		/* Set state of the root hub control pipe as idle */
328 		ehcip->ehci_root_hub.rh_ctrl_pipe_state = EHCI_PIPE_STATE_IDLE;
329 
330 		ehcip->ehci_root_hub.rh_curr_ctrl_reqp = NULL;
331 
332 		USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
333 		    "ehci_handle_root_hub_pipe_open: Root hub control "
334 		    "pipe open succeeded");
335 
336 		break;
337 	case USB_EP_ATTR_INTR:
338 		/* Save interrupt pipe handle */
339 		ehcip->ehci_root_hub.rh_intr_pipe_handle = ph;
340 
341 		/* Set state of the root hub interrupt pipe as idle */
342 		ehcip->ehci_root_hub.rh_intr_pipe_state = EHCI_PIPE_STATE_IDLE;
343 
344 		ehcip->ehci_root_hub.rh_client_intr_reqp = NULL;
345 
346 		ehcip->ehci_root_hub.rh_curr_intr_reqp = NULL;
347 
348 		USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
349 		    "ehci_handle_root_hub_pipe_open: Root hub interrupt "
350 		    "pipe open succeeded");
351 
352 		break;
353 	default:
354 		USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
355 		    "ehci_handle_root_hub_pipe_open: Root hub pipe open"
356 		    "failed");
357 
358 		return (USB_FAILURE);
359 	}
360 
361 	ehcip->ehci_open_pipe_count++;
362 
363 	return (USB_SUCCESS);
364 }
365 
366 
367 /*
368  * ehci_handle_root_hub_pipe_close:
369  *
370  * Handle closing of control and interrupt pipes on root hub.
371  */
372 /* ARGSUSED */
373 int
ehci_handle_root_hub_pipe_close(usba_pipe_handle_data_t * ph)374 ehci_handle_root_hub_pipe_close(usba_pipe_handle_data_t	*ph)
375 {
376 	ehci_state_t		*ehcip = ehci_obtain_state(
377 	    ph->p_usba_device->usb_root_hub_dip);
378 	usb_ep_descr_t		*eptd = &ph->p_ep;
379 
380 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
381 	    "ehci_handle_root_hub_pipe_close: Root hub pipe close");
382 
383 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
384 
385 	switch (eptd->bmAttributes & USB_EP_ATTR_MASK) {
386 	case USB_EP_ATTR_CONTROL:
387 		ASSERT(ehcip->ehci_root_hub.
388 		    rh_ctrl_pipe_state != EHCI_PIPE_STATE_CLOSE);
389 
390 		/* Set state of the root hub control pipe as close */
391 		ehcip->ehci_root_hub.rh_ctrl_pipe_state = EHCI_PIPE_STATE_CLOSE;
392 
393 		/* Set root hub control pipe handle to null */
394 		ehcip->ehci_root_hub.rh_ctrl_pipe_handle = NULL;
395 
396 		USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
397 		    "ehci_handle_root_hub_pipe_close: "
398 		    "Root hub control pipe close succeeded");
399 		break;
400 	case USB_EP_ATTR_INTR:
401 		ASSERT((eptd->bEndpointAddress & USB_EP_NUM_MASK) == 1);
402 
403 		ASSERT(ehcip->ehci_root_hub.
404 		    rh_intr_pipe_state != EHCI_PIPE_STATE_CLOSE);
405 
406 		/* Set state of the root hub interrupt pipe as close */
407 		ehcip->ehci_root_hub.rh_intr_pipe_state = EHCI_PIPE_STATE_CLOSE;
408 
409 		/* Do interrupt pipe cleanup */
410 		ehci_root_hub_intr_pipe_cleanup(ehcip, USB_CR_PIPE_CLOSING);
411 
412 		/* Set root hub interrupt pipe handle to null */
413 		ehcip->ehci_root_hub.rh_intr_pipe_handle = NULL;
414 
415 		USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
416 		    "ehci_handle_root_hub_pipe_close: "
417 		    "Root hub interrupt pipe close succeeded");
418 
419 		break;
420 	default:
421 		USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
422 		    "ehci_handle_root_hub_pipe_close: "
423 		    "Root hub pipe close failed");
424 
425 		return (USB_FAILURE);
426 	}
427 
428 	ehcip->ehci_open_pipe_count--;
429 
430 	return (USB_SUCCESS);
431 }
432 
433 
434 /*
435  * ehci_handle_root_hub_pipe_reset:
436  *
437  * Handle resetting of control and interrupt pipes on root hub.
438  */
439 /* ARGSUSED */
440 int
ehci_handle_root_hub_pipe_reset(usba_pipe_handle_data_t * ph,usb_flags_t usb_flags)441 ehci_handle_root_hub_pipe_reset(
442 	usba_pipe_handle_data_t	*ph,
443 	usb_flags_t		usb_flags)
444 {
445 	ehci_state_t		*ehcip = ehci_obtain_state(
446 	    ph->p_usba_device->usb_root_hub_dip);
447 	usb_ep_descr_t		*eptd = &ph->p_ep;
448 	int			error = USB_SUCCESS;
449 
450 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
451 	    "ehci_handle_root_hub_pipe_reset: Root hub pipe reset");
452 
453 	mutex_enter(&ehcip->ehci_int_mutex);
454 
455 	switch (eptd->bmAttributes & USB_EP_ATTR_MASK) {
456 	case USB_EP_ATTR_CONTROL:
457 		ehcip->ehci_root_hub.rh_ctrl_pipe_state = EHCI_PIPE_STATE_IDLE;
458 
459 		USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
460 		    "ehci_handle_root_hub_pipe_reset: Pipe reset"
461 		    "for the root hub control pipe successful");
462 
463 		break;
464 	case USB_EP_ATTR_INTR:
465 		ASSERT((eptd->bEndpointAddress & USB_EP_NUM_MASK) == 1);
466 
467 		if ((ehcip->ehci_root_hub.rh_client_intr_reqp) &&
468 		    (ehcip->ehci_root_hub.rh_intr_pipe_state !=
469 		    EHCI_PIPE_STATE_IDLE)) {
470 
471 			ehcip->ehci_root_hub.
472 			    rh_intr_pipe_state = EHCI_PIPE_STATE_RESET;
473 
474 			/* Do interrupt pipe cleanup */
475 			ehci_root_hub_intr_pipe_cleanup(
476 			    ehcip, USB_CR_PIPE_RESET);
477 		}
478 
479 		ASSERT(ehcip->ehci_root_hub.
480 		    rh_intr_pipe_state == EHCI_PIPE_STATE_IDLE);
481 
482 		USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
483 		    "ehci_handle_root_hub_pipe_reset: "
484 		    "Pipe reset for root hub interrupt pipe successful");
485 
486 		break;
487 	default:
488 		USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
489 		    "ehci_handle_root_hub_pipe_reset: "
490 		    "Root hub pipe reset failed");
491 
492 		error = USB_FAILURE;
493 		break;
494 	}
495 
496 	mutex_exit(&ehcip->ehci_int_mutex);
497 
498 	return (error);
499 }
500 
501 
502 /*
503  * ehci_handle_root_hub_request:
504  *
505  * Intercept a root hub request. Handle the  root hub request through the
506  * registers
507  */
508 /* ARGSUSED */
509 int
ehci_handle_root_hub_request(ehci_state_t * ehcip,usba_pipe_handle_data_t * ph,usb_ctrl_req_t * ctrl_reqp)510 ehci_handle_root_hub_request(
511 	ehci_state_t		*ehcip,
512 	usba_pipe_handle_data_t	*ph,
513 	usb_ctrl_req_t		*ctrl_reqp)
514 {
515 	uchar_t			bmRequestType = ctrl_reqp->ctrl_bmRequestType;
516 	uchar_t			bRequest = ctrl_reqp->ctrl_bRequest;
517 	uint16_t		wValue = ctrl_reqp->ctrl_wValue;
518 	uint16_t		wIndex = ctrl_reqp->ctrl_wIndex;
519 	uint16_t		wLength = ctrl_reqp->ctrl_wLength;
520 	mblk_t			*data = ctrl_reqp->ctrl_data;
521 	uint16_t		port = wIndex - 1;
522 	usb_cr_t		completion_reason;
523 	int			error = USB_SUCCESS;
524 
525 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
526 	    "ehci_handle_root_hub_request: 0x%x 0x%x 0x%x 0x%x 0x%x 0x%p",
527 	    bmRequestType, bRequest, wValue, wIndex, wLength, (void *)data);
528 
529 	mutex_enter(&ehcip->ehci_int_mutex);
530 
531 	if (ehcip->ehci_root_hub.
532 	    rh_ctrl_pipe_state != EHCI_PIPE_STATE_IDLE) {
533 
534 		USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
535 		    "ehci_handle_root_hub_request: Pipe is not idle");
536 
537 		mutex_exit(&ehcip->ehci_int_mutex);
538 
539 		return (USB_FAILURE);
540 	}
541 
542 	/* Save the current control request pointer */
543 	ehcip->ehci_root_hub.rh_curr_ctrl_reqp = ctrl_reqp;
544 
545 	/* Set pipe state to active */
546 	ehcip->ehci_root_hub.rh_ctrl_pipe_state = EHCI_PIPE_STATE_ACTIVE;
547 
548 	mutex_exit(&ehcip->ehci_int_mutex);
549 
550 	switch (bmRequestType) {
551 	case HUB_GET_DEVICE_STATUS_TYPE:
552 		ehci_handle_get_device_status(ehcip);
553 		break;
554 	case HUB_HANDLE_PORT_FEATURE_TYPE:
555 		error = ehci_handle_set_clear_port_feature(ehcip,
556 		    bRequest, wValue, port);
557 		break;
558 	case HUB_GET_PORT_STATUS_TYPE:
559 		ehci_handle_get_port_status(ehcip, port);
560 		break;
561 	case HUB_CLASS_REQ_TYPE:
562 		switch (bRequest) {
563 		case USB_REQ_GET_STATUS:
564 			ehci_handle_get_hub_status(ehcip);
565 			break;
566 		case USB_REQ_GET_DESCR:
567 			ehci_handle_get_hub_descriptor(ehcip);
568 			break;
569 		default:
570 			USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
571 			    "ehci_handle_root_hub_request:"
572 			    "Unsupported request 0x%x", bRequest);
573 
574 			error = USB_FAILURE;
575 			break;
576 		}
577 		break;
578 	default:
579 		USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
580 		    "ehci_handle_root_hub_request: "
581 		    "Unsupported request 0x%x", bmRequestType);
582 
583 		error = USB_FAILURE;
584 		break;
585 	}
586 
587 	completion_reason = (error) ? USB_CR_NOT_SUPPORTED : USB_CR_OK;
588 
589 	mutex_enter(&ehcip->ehci_int_mutex);
590 	ehci_root_hub_hcdi_callback(ph, completion_reason);
591 	mutex_exit(&ehcip->ehci_int_mutex);
592 
593 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
594 	    "ehci_handle_root_hub_request: error = %d", error);
595 
596 	return (USB_SUCCESS);
597 }
598 
599 
600 /*
601  * ehci_handle_set_clear_port_feature:
602  */
603 static int
ehci_handle_set_clear_port_feature(ehci_state_t * ehcip,uchar_t bRequest,uint16_t wValue,uint16_t port)604 ehci_handle_set_clear_port_feature(
605 	ehci_state_t		*ehcip,
606 	uchar_t 		bRequest,
607 	uint16_t		wValue,
608 	uint16_t		port)
609 {
610 	int			error = USB_SUCCESS;
611 
612 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
613 	    "ehci_handle_set_clear_port_feature: 0x%x 0x%x 0x%x",
614 	    bRequest, wValue, port);
615 
616 	switch (bRequest) {
617 	case USB_REQ_SET_FEATURE:
618 		switch (wValue) {
619 		case CFS_PORT_ENABLE:
620 			ehci_handle_port_enable(ehcip, port, 1);
621 			break;
622 		case CFS_PORT_SUSPEND:
623 			ehci_handle_port_suspend(ehcip, port, 1);
624 			break;
625 		case CFS_PORT_RESET:
626 			ehci_handle_port_reset(ehcip, port);
627 			break;
628 		case CFS_PORT_POWER:
629 			ehci_handle_port_power(ehcip, port, 1);
630 			break;
631 		default:
632 			USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
633 			    "ehci_handle_set_clear_port_feature: "
634 			    "Unsupported request 0x%x 0x%x", bRequest, wValue);
635 
636 			error = USB_FAILURE;
637 			break;
638 		}
639 		break;
640 	case USB_REQ_CLEAR_FEATURE:
641 		switch (wValue) {
642 		case CFS_PORT_ENABLE:
643 			ehci_handle_port_enable(ehcip, port, 0);
644 			break;
645 		case CFS_C_PORT_ENABLE:
646 			ehci_handle_clrchng_port_enable(ehcip, port);
647 			break;
648 		case CFS_PORT_SUSPEND:
649 			ehci_handle_port_suspend(ehcip, port, 0);
650 			break;
651 		case CFS_C_PORT_SUSPEND:
652 			ehci_handle_clrchng_port_suspend(ehcip, port);
653 			break;
654 		case CFS_C_PORT_RESET:
655 			ehci_handle_complete_port_reset(ehcip, port);
656 			break;
657 		case CFS_PORT_POWER:
658 			ehci_handle_port_power(ehcip, port, 0);
659 			break;
660 		case CFS_C_PORT_CONNECTION:
661 			ehci_handle_clear_port_connection(ehcip, port);
662 			break;
663 		case CFS_C_PORT_OVER_CURRENT:
664 			ehci_handle_clrchng_port_over_current(ehcip, port);
665 			break;
666 		default:
667 			USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
668 			    "ehci_handle_set_clear_port_feature: "
669 			    "Unsupported request 0x%x 0x%x", bRequest, wValue);
670 
671 			error = USB_FAILURE;
672 			break;
673 		}
674 		break;
675 	default:
676 		USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
677 		    "ehci_handle_set_clear_port_feature: "
678 		    "Unsupported request 0x%x 0x%x", bRequest, wValue);
679 
680 		error = USB_FAILURE;
681 		break;
682 	}
683 
684 	return (error);
685 }
686 
687 
688 /*
689  * ehci_handle_port_power:
690  *
691  * Turn on a root hub port.
692  */
693 static void
ehci_handle_port_power(ehci_state_t * ehcip,uint16_t port,uint_t on)694 ehci_handle_port_power(
695 	ehci_state_t		*ehcip,
696 	uint16_t		port,
697 	uint_t			on)
698 {
699 	uint_t			port_status;
700 	ehci_root_hub_t		*rh;
701 
702 	mutex_enter(&ehcip->ehci_int_mutex);
703 
704 	port_status = Get_OpReg(ehci_rh_port_status[port]) &
705 	    ~EHCI_RH_PORT_CLEAR_MASK;
706 
707 	rh = &ehcip->ehci_root_hub;
708 
709 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
710 	    "ehci_handle_port_power: port = 0x%x status = 0x%x on = %d",
711 	    port, port_status, on);
712 
713 	/* Check port is owned by ehci */
714 	if (ehci_is_port_owner(ehcip, port) != USB_SUCCESS) {
715 		mutex_exit(&ehcip->ehci_int_mutex);
716 
717 		return;
718 	}
719 
720 	if (on) {
721 		/* See if the port power is already on */
722 		if (!(port_status & EHCI_RH_PORT_POWER)) {
723 			/* Turn the port on */
724 			Set_OpReg(ehci_rh_port_status[port],
725 			    port_status | EHCI_RH_PORT_POWER);
726 		}
727 
728 		rh->rh_port_status[port] = 0;
729 		rh->rh_port_state[port] = DISCONNECTED;
730 	} else {
731 		/* See if the port power is already OFF */
732 		if (port_status & EHCI_RH_PORT_POWER) {
733 			/* Turn-off the port */
734 			Set_OpReg(ehci_rh_port_status[port],
735 			    port_status & ~EHCI_RH_PORT_POWER);
736 		}
737 
738 		rh->rh_port_status[port] = 0;
739 		rh->rh_port_state[port] = POWERED_OFF;
740 	}
741 
742 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
743 	    "ehci_handle_port_power done: port = 0x%x status = 0x%x on = %d",
744 	    port, Get_OpReg(ehci_rh_port_status[port]), on);
745 
746 	mutex_exit(&ehcip->ehci_int_mutex);
747 }
748 
749 
750 /*
751  * ehci_handle_port_enable:
752  *
753  * Handle port enable request.
754  */
755 static void
ehci_handle_port_enable(ehci_state_t * ehcip,uint16_t port,uint_t on)756 ehci_handle_port_enable(
757 	ehci_state_t		*ehcip,
758 	uint16_t		port,
759 	uint_t			on)
760 {
761 	uint_t			port_status;
762 
763 	mutex_enter(&ehcip->ehci_int_mutex);
764 
765 	port_status = Get_OpReg(ehci_rh_port_status[port]) &
766 	    ~EHCI_RH_PORT_CLEAR_MASK;
767 
768 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
769 	    "ehci_handle_port_enable: port = 0x%x, status = 0x%x",
770 	    port, port_status);
771 
772 	/* Check port is owned by ehci */
773 	if (ehci_is_port_owner(ehcip, port) != USB_SUCCESS) {
774 		mutex_exit(&ehcip->ehci_int_mutex);
775 
776 		return;
777 	}
778 
779 	if (on) {
780 		/* See if the port enable is already on */
781 		if (!(port_status & EHCI_RH_PORT_ENABLE)) {
782 			/* Enable the port */
783 			Set_OpReg(ehci_rh_port_status[port],
784 			    port_status | EHCI_RH_PORT_ENABLE);
785 		}
786 	} else {
787 		/* See if the port enable is already off */
788 		if (port_status & EHCI_RH_PORT_ENABLE) {
789 			/* Disable the port */
790 			Set_OpReg(ehci_rh_port_status[port],
791 			    port_status & ~EHCI_RH_PORT_ENABLE);
792 		}
793 	}
794 
795 	mutex_exit(&ehcip->ehci_int_mutex);
796 }
797 
798 
799 /*
800  * ehci_handle_clrchng_port_enable:
801  *
802  * Handle clear port enable change bit.
803  */
804 static void
ehci_handle_clrchng_port_enable(ehci_state_t * ehcip,uint16_t port)805 ehci_handle_clrchng_port_enable(
806 	ehci_state_t		*ehcip,
807 	uint16_t		port)
808 {
809 	uint_t			port_status;
810 
811 	mutex_enter(&ehcip->ehci_int_mutex);
812 
813 	port_status = Get_OpReg(ehci_rh_port_status[port]) &
814 	    ~EHCI_RH_PORT_CLEAR_MASK;
815 
816 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
817 	    "ehci_handle_port_enable: port = 0x%x, status = 0x%x",
818 	    port, port_status);
819 
820 	/* Check port is owned by ehci */
821 	if (ehci_is_port_owner(ehcip, port) != USB_SUCCESS) {
822 		mutex_exit(&ehcip->ehci_int_mutex);
823 
824 		return;
825 	}
826 
827 	/* Clear the PortEnableStatusChange Bit */
828 	Set_OpReg(ehci_rh_port_status[port],
829 	    port_status | EHCI_RH_PORT_ENABLE_CHANGE);
830 
831 	mutex_exit(&ehcip->ehci_int_mutex);
832 }
833 
834 
835 /*
836  * ehci_handle_port_suspend:
837  *
838  * Handle port suspend/resume request.
839  */
840 static void
ehci_handle_port_suspend(ehci_state_t * ehcip,uint16_t port,uint_t on)841 ehci_handle_port_suspend(
842 	ehci_state_t		*ehcip,
843 	uint16_t		port,
844 	uint_t			on)
845 {
846 	uint_t			port_status;
847 
848 	mutex_enter(&ehcip->ehci_int_mutex);
849 
850 	port_status = Get_OpReg(ehci_rh_port_status[port]) &
851 	    ~EHCI_RH_PORT_CLEAR_MASK;
852 
853 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
854 	    "ehci_handle_port_suspend: port = 0x%x, status = 0x%x",
855 	    port, port_status);
856 
857 	/* Check port is owned by ehci */
858 	if (ehci_is_port_owner(ehcip, port) != USB_SUCCESS) {
859 		mutex_exit(&ehcip->ehci_int_mutex);
860 
861 		return;
862 	}
863 
864 	if (on) {
865 		/*
866 		 * Suspend port only if port is enabled and
867 		 * it is not already in suspend state.
868 		 */
869 		if ((port_status & EHCI_RH_PORT_ENABLE) &&
870 		    (!(port_status & EHCI_RH_PORT_SUSPEND))) {
871 			/* Suspend the port */
872 			Set_OpReg(ehci_rh_port_status[port],
873 			    port_status | EHCI_RH_PORT_SUSPEND);
874 
875 			mutex_exit(&ehcip->ehci_int_mutex);
876 
877 			/* Wait 10ms for port move to suspend state */
878 			delay(drv_usectohz(EHCI_PORT_SUSPEND_TIMEWAIT));
879 
880 			return;
881 		}
882 	} else {
883 		/* Perform resume only if port is in suspend state */
884 		if (port_status & EHCI_RH_PORT_SUSPEND) {
885 			/* Resume the port */
886 			Set_OpReg(ehci_rh_port_status[port],
887 			    port_status | EHCI_RH_PORT_RESUME);
888 		}
889 	}
890 
891 	mutex_exit(&ehcip->ehci_int_mutex);
892 }
893 
894 
895 /*
896  * ehci_handle_clrchng_port_suspend:
897  *
898  * Handle port clear port suspend change bit.
899  */
900 static void
ehci_handle_clrchng_port_suspend(ehci_state_t * ehcip,uint16_t port)901 ehci_handle_clrchng_port_suspend(
902 	ehci_state_t		*ehcip,
903 	uint16_t		port)
904 {
905 	uint_t			port_status;
906 	int			i;
907 
908 	mutex_enter(&ehcip->ehci_int_mutex);
909 
910 	port_status = Get_OpReg(ehci_rh_port_status[port]) &
911 	    ~EHCI_RH_PORT_CLEAR_MASK;
912 
913 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
914 	    "ehci_handle_clrchng_port_suspend: port = 0x%x, "
915 	    "status = 0x%x", port, port_status);
916 
917 	/* Check port is owned by ehci */
918 	if (ehci_is_port_owner(ehcip, port) != USB_SUCCESS) {
919 		mutex_exit(&ehcip->ehci_int_mutex);
920 
921 		return;
922 	}
923 
924 	/* Return if port is not in resume state */
925 	if (!(port_status & EHCI_RH_PORT_RESUME)) {
926 		mutex_exit(&ehcip->ehci_int_mutex);
927 
928 		return;
929 	}
930 
931 	mutex_exit(&ehcip->ehci_int_mutex);
932 
933 	/* Wait for 20ms to terminate resume */
934 	delay(drv_usectohz(EHCI_PORT_RESUME_TIMEWAIT));
935 
936 	mutex_enter(&ehcip->ehci_int_mutex);
937 
938 	Set_OpReg(ehci_rh_port_status[port],
939 	    port_status & ~EHCI_RH_PORT_RESUME);
940 
941 	mutex_exit(&ehcip->ehci_int_mutex);
942 
943 	/*
944 	 * Wait for port to return to high speed mode. It's necessary to poll
945 	 * for resume completion for some high-speed devices to work correctly.
946 	 */
947 	for (i = 0; i < EHCI_PORT_RESUME_RETRY_MAX; i++) {
948 		delay(drv_usectohz(EHCI_PORT_RESUME_COMP_TIMEWAIT));
949 
950 		mutex_enter(&ehcip->ehci_int_mutex);
951 		port_status = Get_OpReg(ehci_rh_port_status[port]) &
952 		    ~EHCI_RH_PORT_CLEAR_MASK;
953 		mutex_exit(&ehcip->ehci_int_mutex);
954 
955 		if (!(port_status & EHCI_RH_PORT_RESUME)) {
956 			break;
957 		}
958 	}
959 }
960 
961 
962 /*
963  * ehci_handle_port_reset:
964  *
965  * Perform a port reset.
966  */
967 static void
ehci_handle_port_reset(ehci_state_t * ehcip,uint16_t port)968 ehci_handle_port_reset(
969 	ehci_state_t		*ehcip,
970 	uint16_t		port)
971 {
972 	ehci_root_hub_t		*rh;
973 	uint_t			port_status;
974 	int			i;
975 
976 	mutex_enter(&ehcip->ehci_int_mutex);
977 
978 	/* Get the root hub structure */
979 	rh = &ehcip->ehci_root_hub;
980 
981 	/* Get the port status information */
982 	port_status = Get_OpReg(ehci_rh_port_status[port]) &
983 	    ~EHCI_RH_PORT_CLEAR_MASK;
984 
985 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
986 	    "ehci_handle_port_reset: port = 0x%x status = 0x%x",
987 	    port, port_status);
988 
989 	/* Check port is owned by ehci */
990 	if (ehci_is_port_owner(ehcip, port) != USB_SUCCESS) {
991 		mutex_exit(&ehcip->ehci_int_mutex);
992 
993 		return;
994 	}
995 
996 	if (port_status & EHCI_RH_PORT_LOW_SPEED) {
997 		/* Check for classic or companion host controllers */
998 		if (rh->rh_companion_controllers) {
999 			USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
1000 			    "ehci_handle_port_reset: Low speed device "
1001 			    "and handover this port to Companion controller");
1002 
1003 			Set_OpReg(ehci_rh_port_status[port],
1004 			    port_status | EHCI_RH_PORT_OWNER_CLASSIC);
1005 		} else {
1006 			USB_DPRINTF_L1(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
1007 			    "Low speed device is not supported");
1008 		}
1009 	} else {
1010 		Set_OpReg(ehci_rh_port_status[port],
1011 		    ((port_status | EHCI_RH_PORT_RESET) &
1012 		    ~EHCI_RH_PORT_ENABLE));
1013 
1014 		mutex_exit(&ehcip->ehci_int_mutex);
1015 
1016 		/* Wait 50ms for reset to complete */
1017 		delay(drv_usectohz(EHCI_PORT_RESET_TIMEWAIT));
1018 
1019 		mutex_enter(&ehcip->ehci_int_mutex);
1020 
1021 		port_status = Get_OpReg(ehci_rh_port_status[port]) &
1022 		    ~EHCI_RH_PORT_CLEAR_MASK;
1023 
1024 		Set_OpReg(ehci_rh_port_status[port],
1025 		    (port_status & ~EHCI_RH_PORT_RESET));
1026 
1027 		mutex_exit(&ehcip->ehci_int_mutex);
1028 
1029 		/*
1030 		 * Wait for hardware to enable this port, if the connected
1031 		 * usb device is high speed. It's necessary to poll for reset
1032 		 * completion for some high-speed devices to recognized
1033 		 * correctly.
1034 		 */
1035 		for (i = 0; i < EHCI_PORT_RESET_RETRY_MAX; i++) {
1036 			delay(drv_usectohz(EHCI_PORT_RESET_COMP_TIMEWAIT));
1037 
1038 			mutex_enter(&ehcip->ehci_int_mutex);
1039 			port_status = Get_OpReg(ehci_rh_port_status[port]) &
1040 			    ~EHCI_RH_PORT_CLEAR_MASK;
1041 			mutex_exit(&ehcip->ehci_int_mutex);
1042 
1043 			if (!(port_status & EHCI_RH_PORT_RESET)) {
1044 				break;
1045 			}
1046 		}
1047 
1048 		mutex_enter(&ehcip->ehci_int_mutex);
1049 
1050 		port_status = Get_OpReg(ehci_rh_port_status[port]) &
1051 		    ~EHCI_RH_PORT_CLEAR_MASK;
1052 
1053 		/*
1054 		 * If port is not enabled, connected device is a
1055 		 * Full-speed usb device.
1056 		 */
1057 		if (!(port_status & EHCI_RH_PORT_ENABLE)) {
1058 			/* Check for classic or companion host controllers */
1059 			if (rh->rh_companion_controllers) {
1060 				USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB,
1061 				    ehcip->ehci_log_hdl,
1062 				    "ehci_handle_port_reset: Full speed device "
1063 				    "and handover this port to Companion host "
1064 				    "controller");
1065 
1066 				Set_OpReg(ehci_rh_port_status[port],
1067 				    port_status | EHCI_RH_PORT_OWNER_CLASSIC);
1068 			} else {
1069 				USB_DPRINTF_L1(PRINT_MASK_ROOT_HUB,
1070 				    ehcip->ehci_log_hdl,
1071 				    "Full speed device is not supported");
1072 			}
1073 		} else {
1074 			USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
1075 			    "ehci_handle_port_reset: High speed device ");
1076 
1077 			port_status = Get_OpReg(ehci_rh_port_status[port]) &
1078 			    ~EHCI_RH_PORT_CLEAR_MASK;
1079 
1080 			/*
1081 			 * Disable over-current, connect, and disconnect
1082 			 * wakeup bits.
1083 			 */
1084 			Set_OpReg(ehci_rh_port_status[port], port_status &
1085 			    ~(EHCI_RH_PORT_OVER_CURENT_ENABLE |
1086 			    EHCI_RH_PORT_DISCONNECT_ENABLE |
1087 			    EHCI_RH_PORT_CONNECT_ENABLE));
1088 
1089 			/*
1090 			 * The next function is only called if the interrupt
1091 			 * pipe is polling and the USBA is ready to receive
1092 			 * the data.
1093 			 */
1094 			ehcip->ehci_root_hub.
1095 			    rh_intr_pending_status |= (1 << port);
1096 
1097 			if (ehcip->ehci_root_hub.
1098 			    rh_intr_pipe_state == EHCI_PIPE_STATE_ACTIVE) {
1099 
1100 				ehci_root_hub_reset_occured(ehcip);
1101 			}
1102 		}
1103 	}
1104 
1105 	mutex_exit(&ehcip->ehci_int_mutex);
1106 }
1107 
1108 
1109 /*
1110  * ehci_root_hub_reset_occured:
1111  *
1112  * Inform the upper layer that reset has occured on the port. This is
1113  * required because the upper layer is expecting a an evernt immidiately
1114  * after doing reset. In case of OHCI, the controller gets an interrupt
1115  * for the change in the root hub status but in case of EHCI, we dont.
1116  * So, send a event to the upper layer as soon as we complete the reset.
1117  */
1118 void
ehci_root_hub_reset_occured(ehci_state_t * ehcip)1119 ehci_root_hub_reset_occured(
1120 	ehci_state_t		*ehcip)
1121 {
1122 	usb_intr_req_t		*curr_intr_reqp =
1123 	    ehcip->ehci_root_hub.rh_curr_intr_reqp;
1124 	usb_port_mask_t		port_mask;
1125 	usba_pipe_handle_data_t	*ph;
1126 
1127 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
1128 	    "ehci_root_hub_reset_occured: curr_intr_reqp = 0x%p data = 0x%p",
1129 	    (void *)curr_intr_reqp, (void *)curr_intr_reqp->intr_data);
1130 
1131 	/* Get the interrupt pipe handle */
1132 	ph = ehcip->ehci_root_hub.rh_intr_pipe_handle;
1133 
1134 	/* Get the pending status */
1135 	port_mask = ehcip->ehci_root_hub.rh_intr_pending_status << 1;
1136 
1137 	do {
1138 		*curr_intr_reqp->intr_data->b_wptr++ = (uchar_t)port_mask;
1139 		port_mask >>= 8;
1140 	} while (port_mask != 0);
1141 
1142 	ehci_root_hub_hcdi_callback(ph, USB_CR_OK);
1143 
1144 	/* Reset pending status */
1145 	ehcip->ehci_root_hub.rh_intr_pending_status = 0;
1146 
1147 	/* If needed, allocate new interrupt request */
1148 	if ((ehci_root_hub_allocate_intr_pipe_resource(
1149 	    ehcip, 0)) != USB_SUCCESS) {
1150 
1151 		/* Do interrupt pipe cleanup */
1152 		ehci_root_hub_intr_pipe_cleanup(ehcip, USB_CR_NO_RESOURCES);
1153 	}
1154 }
1155 
1156 
1157 /*
1158  * ehci_handle_complete_port_reset:
1159  *
1160  * Perform a port reset change.
1161  */
1162 static void
ehci_handle_complete_port_reset(ehci_state_t * ehcip,uint16_t port)1163 ehci_handle_complete_port_reset(
1164 	ehci_state_t		*ehcip,
1165 	uint16_t		port)
1166 {
1167 	uint_t			port_status;
1168 
1169 	mutex_enter(&ehcip->ehci_int_mutex);
1170 
1171 	port_status = Get_OpReg(ehci_rh_port_status[port]) &
1172 	    ~EHCI_RH_PORT_CLEAR_MASK;
1173 
1174 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
1175 	    "ehci_handle_complete_port_reset: port = 0x%x status = 0x%x",
1176 	    port, port_status);
1177 
1178 	/* Check port is owned by ehci */
1179 	if (ehci_is_port_owner(ehcip, port) != USB_SUCCESS) {
1180 		mutex_exit(&ehcip->ehci_int_mutex);
1181 
1182 		return;
1183 	}
1184 
1185 	if (port_status & EHCI_RH_PORT_RESET) {
1186 		Set_OpReg(ehci_rh_port_status[port],
1187 		    port_status & ~EHCI_RH_PORT_RESET);
1188 
1189 	}
1190 
1191 	mutex_exit(&ehcip->ehci_int_mutex);
1192 }
1193 
1194 
1195 /*
1196  * ehci_handle_clear_port_connection:
1197  *
1198  * Perform a clear port connection.
1199  */
1200 static void
ehci_handle_clear_port_connection(ehci_state_t * ehcip,uint16_t port)1201 ehci_handle_clear_port_connection(
1202 	ehci_state_t		*ehcip,
1203 	uint16_t		port)
1204 {
1205 	uint_t			port_status;
1206 
1207 	mutex_enter(&ehcip->ehci_int_mutex);
1208 
1209 	port_status = Get_OpReg(ehci_rh_port_status[port]) &
1210 	    ~EHCI_RH_PORT_CLEAR_MASK;
1211 
1212 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
1213 	    "ehci_handle_clear_port_connection: port = 0x%x"
1214 	    "status = 0x%x", port, port_status);
1215 
1216 	Set_OpReg(ehci_rh_port_status[port],
1217 	    port_status | EHCI_RH_PORT_CONNECT_STS_CHANGE);
1218 
1219 	mutex_exit(&ehcip->ehci_int_mutex);
1220 }
1221 
1222 
1223 /*
1224  * ehci_handle_clrchng_port_over_current:
1225  *
1226  * Perform a clear port connection.
1227  */
1228 static void
ehci_handle_clrchng_port_over_current(ehci_state_t * ehcip,uint16_t port)1229 ehci_handle_clrchng_port_over_current(
1230 	ehci_state_t		*ehcip,
1231 	uint16_t		port)
1232 {
1233 	uint_t			port_status;
1234 
1235 	mutex_enter(&ehcip->ehci_int_mutex);
1236 
1237 	port_status = Get_OpReg(ehci_rh_port_status[port]) &
1238 	    ~EHCI_RH_PORT_CLEAR_MASK;
1239 
1240 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
1241 	    "ehci_handle_clrchng_port_over_current: port = 0x%x"
1242 	    "status = 0x%x", port, port_status);
1243 
1244 	Set_OpReg(ehci_rh_port_status[port],
1245 	    port_status | EHCI_RH_PORT_OVER_CURR_CHANGE);
1246 
1247 	mutex_exit(&ehcip->ehci_int_mutex);
1248 }
1249 
1250 
1251 /*
1252  * ehci_handle_get_port_status:
1253  *
1254  * Handle a get port status request.
1255  */
1256 static void
ehci_handle_get_port_status(ehci_state_t * ehcip,uint16_t port)1257 ehci_handle_get_port_status(
1258 	ehci_state_t		*ehcip,
1259 	uint16_t		port)
1260 {
1261 	usb_ctrl_req_t		*ctrl_reqp;
1262 	mblk_t			*message;
1263 	uint_t			new_port_status = 0;
1264 	uint_t			change_status = 0;
1265 	uint_t			port_status;
1266 
1267 	mutex_enter(&ehcip->ehci_int_mutex);
1268 
1269 	ctrl_reqp = ehcip->ehci_root_hub.rh_curr_ctrl_reqp;
1270 
1271 	/* Get the root hub port status information */
1272 	port_status = ehci_get_root_hub_port_status(ehcip, port);
1273 
1274 	new_port_status = port_status & PORT_STATUS_MASK;
1275 	change_status = (port_status >> 16) & PORT_CHANGE_MASK;
1276 
1277 	ehcip->ehci_root_hub.rh_port_status[port] = new_port_status;
1278 
1279 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
1280 	    "ehci_handle_get_port_status: port = %d new status = 0x%x"
1281 	    "change = 0x%x", port, new_port_status, change_status);
1282 
1283 	message = ctrl_reqp->ctrl_data;
1284 
1285 	ASSERT(message != NULL);
1286 
1287 	*message->b_wptr++ = (uchar_t)new_port_status;
1288 	*message->b_wptr++ = (uchar_t)(new_port_status >> 8);
1289 	*message->b_wptr++ = (uchar_t)change_status;
1290 	*message->b_wptr++ = (uchar_t)(change_status >> 8);
1291 
1292 	/* Save the data in control request */
1293 	ctrl_reqp->ctrl_data = message;
1294 
1295 	mutex_exit(&ehcip->ehci_int_mutex);
1296 }
1297 
1298 
1299 /*
1300  * ehci_handle_get_hub_descriptor:
1301  */
1302 static void
ehci_handle_get_hub_descriptor(ehci_state_t * ehcip)1303 ehci_handle_get_hub_descriptor(
1304 	ehci_state_t		*ehcip)
1305 {
1306 	usb_ctrl_req_t		*ctrl_reqp;
1307 	mblk_t			*message;
1308 	usb_hub_descr_t		*root_hub_descr;
1309 	size_t			length;
1310 	uchar_t			raw_descr[ROOT_HUB_DESCRIPTOR_LENGTH];
1311 
1312 	mutex_enter(&ehcip->ehci_int_mutex);
1313 
1314 	ctrl_reqp = ehcip->ehci_root_hub.rh_curr_ctrl_reqp;
1315 	root_hub_descr = &ehcip->ehci_root_hub.rh_descr;
1316 	length = ctrl_reqp->ctrl_wLength;
1317 
1318 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
1319 	    "ehci_handle_get_hub_descriptor: Ctrl Req  = 0x%p",
1320 	    (void *)ctrl_reqp);
1321 
1322 	message = ctrl_reqp->ctrl_data;
1323 
1324 	ASSERT(message != NULL);
1325 
1326 	bzero(&raw_descr, ROOT_HUB_DESCRIPTOR_LENGTH);
1327 
1328 	raw_descr[0] = root_hub_descr->bDescLength;
1329 	raw_descr[1] = root_hub_descr->bDescriptorType;
1330 	raw_descr[2] = root_hub_descr->bNbrPorts;
1331 	raw_descr[3] = root_hub_descr->wHubCharacteristics & 0x00FF;
1332 	raw_descr[4] = (root_hub_descr->wHubCharacteristics & 0xFF00) >> 8;
1333 	raw_descr[5] = root_hub_descr->bPwrOn2PwrGood;
1334 	raw_descr[6] = root_hub_descr->bHubContrCurrent;
1335 	raw_descr[7] = root_hub_descr->DeviceRemovable;
1336 	raw_descr[8] = root_hub_descr->PortPwrCtrlMask;
1337 
1338 	bcopy(raw_descr, message->b_wptr, length);
1339 	message->b_wptr += length;
1340 
1341 	/* Save the data in control request */
1342 	ctrl_reqp->ctrl_data = message;
1343 
1344 	mutex_exit(&ehcip->ehci_int_mutex);
1345 }
1346 
1347 
1348 /*
1349  * ehci_handle_get_hub_status:
1350  *
1351  * Handle a get hub status request.
1352  */
1353 static void
ehci_handle_get_hub_status(ehci_state_t * ehcip)1354 ehci_handle_get_hub_status(
1355 	ehci_state_t		*ehcip)
1356 {
1357 	usb_ctrl_req_t		*ctrl_reqp;
1358 	mblk_t			*message;
1359 	uint_t			new_root_hub_status;
1360 
1361 	mutex_enter(&ehcip->ehci_int_mutex);
1362 
1363 	ctrl_reqp = ehcip->ehci_root_hub.rh_curr_ctrl_reqp;
1364 
1365 	/*
1366 	 * For EHCI, there is no overall hub status information.
1367 	 * Only individual root hub port status information is
1368 	 * available. So return zero for the root hub status
1369 	 * request.
1370 	 */
1371 	new_root_hub_status = 0;
1372 
1373 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
1374 	    "ehci_handle_get_hub_status: new root hub status = 0x%x",
1375 	    new_root_hub_status);
1376 
1377 	message = ctrl_reqp->ctrl_data;
1378 
1379 	ASSERT(message != NULL);
1380 
1381 	*message->b_wptr++ = (uchar_t)new_root_hub_status;
1382 	*message->b_wptr++ = (uchar_t)(new_root_hub_status >> 8);
1383 	*message->b_wptr++ = (uchar_t)(new_root_hub_status >> 16);
1384 	*message->b_wptr++ = (uchar_t)(new_root_hub_status >> 24);
1385 
1386 	/* Save the data in control request */
1387 	ctrl_reqp->ctrl_data = message;
1388 
1389 	mutex_exit(&ehcip->ehci_int_mutex);
1390 }
1391 
1392 
1393 /*
1394  * ehci_handle_get_device_status:
1395  *
1396  * Handle a get device status request.
1397  */
1398 static void
ehci_handle_get_device_status(ehci_state_t * ehcip)1399 ehci_handle_get_device_status(
1400 	ehci_state_t		*ehcip)
1401 {
1402 	usb_ctrl_req_t		*ctrl_reqp;
1403 	mblk_t			*message;
1404 	uint16_t		dev_status;
1405 
1406 	mutex_enter(&ehcip->ehci_int_mutex);
1407 
1408 	ctrl_reqp = ehcip->ehci_root_hub.rh_curr_ctrl_reqp;
1409 
1410 	/*
1411 	 * For EHCI, there is no device status information.
1412 	 * Simply return what is desired for the request.
1413 	 */
1414 	dev_status = USB_DEV_SLF_PWRD_STATUS;
1415 
1416 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
1417 	    "ehci_handle_get_device_status: device status = 0x%x",
1418 	    dev_status);
1419 
1420 	message = ctrl_reqp->ctrl_data;
1421 
1422 	ASSERT(message != NULL);
1423 
1424 	*message->b_wptr++ = (uchar_t)dev_status;
1425 	*message->b_wptr++ = (uchar_t)(dev_status >> 8);
1426 
1427 	/* Save the data in control request */
1428 	ctrl_reqp->ctrl_data = message;
1429 
1430 	mutex_exit(&ehcip->ehci_int_mutex);
1431 }
1432 
1433 
1434 /*
1435  * ehci_handle_root_hub_pipe_start_intr_polling:
1436  *
1437  * Handle start polling on root hub interrupt pipe.
1438  */
1439 /* ARGSUSED */
1440 int
ehci_handle_root_hub_pipe_start_intr_polling(usba_pipe_handle_data_t * ph,usb_intr_req_t * client_intr_reqp,usb_flags_t flags)1441 ehci_handle_root_hub_pipe_start_intr_polling(
1442 	usba_pipe_handle_data_t	*ph,
1443 	usb_intr_req_t		*client_intr_reqp,
1444 	usb_flags_t		flags)
1445 {
1446 	ehci_state_t		*ehcip = ehci_obtain_state(
1447 	    ph->p_usba_device->usb_root_hub_dip);
1448 	usb_ep_descr_t		*eptd = &ph->p_ep;
1449 	int			error = USB_SUCCESS;
1450 	uint_t			pipe_state;
1451 
1452 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
1453 	    "ehci_handle_root_hub_pipe_start_intr_polling: "
1454 	    "Root hub pipe start polling");
1455 
1456 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
1457 
1458 	ASSERT((eptd->bEndpointAddress & USB_EP_NUM_MASK) == 1);
1459 
1460 	ASSERT((client_intr_reqp->intr_attributes & USB_ATTRS_ONE_XFER) == 0);
1461 
1462 	pipe_state = ehcip->ehci_root_hub.rh_intr_pipe_state;
1463 
1464 	switch (pipe_state) {
1465 	case EHCI_PIPE_STATE_IDLE:
1466 		ASSERT(ehcip->ehci_root_hub.rh_intr_pipe_timer_id == 0);
1467 
1468 		/*
1469 		 * Save the Original Client's Interrupt IN request
1470 		 * information. We use this for final callback
1471 		 */
1472 		ASSERT(ehcip->ehci_root_hub.rh_client_intr_reqp == NULL);
1473 		ehcip->ehci_root_hub.rh_client_intr_reqp = client_intr_reqp;
1474 
1475 		error = ehci_root_hub_allocate_intr_pipe_resource(ehcip, flags);
1476 
1477 		if (error != USB_SUCCESS) {
1478 			/* Reset client interrupt request pointer */
1479 			ehcip->ehci_root_hub.rh_client_intr_reqp = NULL;
1480 
1481 			USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
1482 			    "ehci_handle_root_hub_pipe_start_intr_polling: "
1483 			    "No Resources");
1484 
1485 			return (error);
1486 		}
1487 
1488 		/* Check whether we need to send the reset data up */
1489 		if (ehcip->ehci_root_hub.rh_intr_pending_status) {
1490 			ehci_root_hub_reset_occured(ehcip);
1491 		}
1492 
1493 		USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
1494 		    "ehci_handle_root_hub_pipe_start_intr_polling: "
1495 		    "Start polling for root hub successful");
1496 
1497 		break;
1498 	case EHCI_PIPE_STATE_ACTIVE:
1499 		USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
1500 		    "ehci_handle_root_hub_pipe_start_intr_polling: "
1501 		    "Polling for root hub is already in progress");
1502 
1503 		break;
1504 	default:
1505 		USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
1506 		    "ehci_handle_root_hub_pipe_start_intr_polling: "
1507 		    "Pipe is in error state 0x%x", pipe_state);
1508 
1509 		error = USB_FAILURE;
1510 
1511 		break;
1512 	}
1513 
1514 	return (error);
1515 }
1516 
1517 
1518 /*
1519  * ehci_handle_root_hub_pipe_stop_intr_polling:
1520  *
1521  * Handle stop polling on root hub intr pipe.
1522  */
1523 /* ARGSUSED */
1524 void
ehci_handle_root_hub_pipe_stop_intr_polling(usba_pipe_handle_data_t * ph,usb_flags_t flags)1525 ehci_handle_root_hub_pipe_stop_intr_polling(
1526 	usba_pipe_handle_data_t	*ph,
1527 	usb_flags_t		flags)
1528 {
1529 	ehci_state_t		*ehcip = ehci_obtain_state(
1530 	    ph->p_usba_device->usb_root_hub_dip);
1531 	usb_ep_descr_t		*eptd = &ph->p_ep;
1532 
1533 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
1534 
1535 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
1536 	    "ehci_handle_root_hub_pipe_stop_intr_polling: "
1537 	    "Root hub pipe stop polling");
1538 
1539 	ASSERT((eptd->bEndpointAddress & USB_EP_NUM_MASK) == 1);
1540 
1541 	if (ehcip->ehci_root_hub.rh_intr_pipe_state ==
1542 	    EHCI_PIPE_STATE_ACTIVE) {
1543 
1544 		ehcip->ehci_root_hub.rh_intr_pipe_state =
1545 		    EHCI_PIPE_STATE_STOP_POLLING;
1546 
1547 		/* Do interrupt pipe cleanup */
1548 		ehci_root_hub_intr_pipe_cleanup(ehcip, USB_CR_STOPPED_POLLING);
1549 
1550 		ASSERT(ehcip->ehci_root_hub.
1551 		    rh_intr_pipe_state == EHCI_PIPE_STATE_IDLE);
1552 
1553 		USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
1554 		    "ehci_hcdi_pipe_stop_intr_polling: Stop polling for root"
1555 		    "hub successful");
1556 	} else {
1557 		USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB,
1558 		    ehcip->ehci_log_hdl, "ehci_hcdi_pipe_stop_intr_polling: "
1559 		    "Polling for root hub is already stopped");
1560 	}
1561 }
1562 
1563 
1564 /*
1565  * ehci_get_root_hub_port_status:
1566  *
1567  * Construct root hub port status and change information
1568  */
1569 static uint_t
ehci_get_root_hub_port_status(ehci_state_t * ehcip,uint16_t port)1570 ehci_get_root_hub_port_status(
1571 	ehci_state_t		*ehcip,
1572 	uint16_t		port)
1573 {
1574 	uint_t			new_port_status = 0;
1575 	uint_t			change_status = 0;
1576 	uint_t			port_status;
1577 
1578 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
1579 
1580 	/* Read the current port status */
1581 	port_status = Get_OpReg(ehci_rh_port_status[port]);
1582 
1583 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
1584 	    "ehci_get_root_hub_port_status: port %d "
1585 	    "port status = 0x%x", port, port_status);
1586 
1587 	/*
1588 	 * EHCI root hub port status and control register information
1589 	 * format is different what Hub driver wants. So EHCI driver
1590 	 * needs to contruct the proper root hub port status information.
1591 	 *
1592 	 * Send all port status information only if port is owned by EHCI
1593 	 * host controller.
1594 	 */
1595 	if ((port_status & EHCI_RH_PORT_OWNER) == EHCI_RH_PORT_OWNER_EHCI) {
1596 
1597 		/* First construct port change information */
1598 		if (port_status & EHCI_RH_PORT_ENABLE_CHANGE) {
1599 			change_status |= PORT_CHANGE_PESC;
1600 		}
1601 
1602 		if (port_status & EHCI_RH_PORT_RESUME) {
1603 			change_status |= PORT_CHANGE_PSSC;
1604 		}
1605 
1606 		if (port_status & EHCI_RH_PORT_OVER_CURR_CHANGE) {
1607 			change_status |= PORT_CHANGE_OCIC;
1608 		}
1609 
1610 		/* Now construct port status information */
1611 		if (port_status & EHCI_RH_PORT_CONNECT_STATUS) {
1612 			new_port_status |= PORT_STATUS_CCS;
1613 		}
1614 
1615 		if (port_status & EHCI_RH_PORT_ENABLE) {
1616 			new_port_status |=
1617 			    (PORT_STATUS_PES | PORT_STATUS_HSDA);
1618 		}
1619 
1620 		if (port_status & EHCI_RH_PORT_SUSPEND) {
1621 			new_port_status |= PORT_STATUS_PSS;
1622 		}
1623 
1624 		if (port_status & EHCI_RH_PORT_OVER_CURR_ACTIVE) {
1625 			new_port_status |= PORT_STATUS_POCI;
1626 		}
1627 
1628 		if (port_status & EHCI_RH_PORT_RESET) {
1629 			new_port_status |= PORT_STATUS_PRS;
1630 		}
1631 
1632 		if (port_status & EHCI_RH_PORT_INDICATOR) {
1633 			new_port_status |= PORT_STATUS_PIC;
1634 		}
1635 	}
1636 
1637 	/*
1638 	 * Send the following port status and change information
1639 	 * even if port is not owned by EHCI.
1640 	 *
1641 	 * Additional port change information.
1642 	 */
1643 	if (port_status & EHCI_RH_PORT_CONNECT_STS_CHANGE) {
1644 		change_status |= PORT_CHANGE_CSC;
1645 	}
1646 
1647 	/* Additional port status information */
1648 	if (port_status & EHCI_RH_PORT_POWER) {
1649 		new_port_status |= PORT_STATUS_PPS;
1650 	}
1651 
1652 	if ((!(port_status & EHCI_RH_PORT_ENABLE)) &&
1653 	    (port_status & EHCI_RH_PORT_LOW_SPEED)) {
1654 		new_port_status |= PORT_STATUS_LSDA;
1655 	}
1656 
1657 	/*
1658 	 * Construct complete root hub port status and change information.
1659 	 */
1660 	port_status = ((change_status << 16) | new_port_status);
1661 
1662 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
1663 	    "ehci_get_root_hub_port_status: port = %d new status = 0x%x "
1664 	    "change status = 0x%x complete port status 0x%x", port,
1665 	    new_port_status, change_status, port_status);
1666 
1667 	return (port_status);
1668 }
1669 
1670 
1671 /*
1672  * ehci_is_port_owner:
1673  *
1674  * Check whether given port is owned by ehci.
1675  */
1676 static int
ehci_is_port_owner(ehci_state_t * ehcip,uint16_t port)1677 ehci_is_port_owner(
1678 	ehci_state_t		*ehcip,
1679 	uint16_t		port)
1680 {
1681 	uint_t			port_status;
1682 
1683 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
1684 
1685 	port_status = Get_OpReg(ehci_rh_port_status[port]) &
1686 	    ~EHCI_RH_PORT_CLEAR_MASK;
1687 
1688 	/*
1689 	 * Don't perform anything if port is owned by classis host
1690 	 * controller and return success.
1691 	 */
1692 	if ((port_status & EHCI_RH_PORT_OWNER) == EHCI_RH_PORT_OWNER_CLASSIC) {
1693 
1694 		USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
1695 		    "ehci_handle_set_clear_port_feature: "
1696 		    "Port %d is owned by classic host controller", port);
1697 
1698 		return (USB_FAILURE);
1699 	}
1700 
1701 	return (USB_SUCCESS);
1702 }
1703 
1704 
1705 /*
1706  * ehci_root_hub_allocate_intr_pipe_resource:
1707  *
1708  * Allocate interrupt requests and initialize them.
1709  */
1710 static int
ehci_root_hub_allocate_intr_pipe_resource(ehci_state_t * ehcip,usb_flags_t flags)1711 ehci_root_hub_allocate_intr_pipe_resource(
1712 	ehci_state_t		*ehcip,
1713 	usb_flags_t		flags)
1714 {
1715 	usba_pipe_handle_data_t	*ph;
1716 	size_t			length;
1717 	usb_intr_req_t		*curr_intr_reqp;
1718 
1719 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
1720 	    "ehci_root_hub_allocate_intr_pipe_resource");
1721 
1722 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
1723 
1724 	/* Get the interrupt pipe handle */
1725 	ph = ehcip->ehci_root_hub.rh_intr_pipe_handle;
1726 
1727 	/* Get the current interrupt request pointer */
1728 	curr_intr_reqp = ehcip->ehci_root_hub.rh_curr_intr_reqp;
1729 
1730 	/*
1731 	 * If current interrupt request pointer is null,
1732 	 * allocate new interrupt request.
1733 	 */
1734 	if (curr_intr_reqp == NULL) {
1735 		ASSERT(ehcip->ehci_root_hub.rh_client_intr_reqp);
1736 
1737 		/* Get the length of interrupt transfer */
1738 		length = ehcip->ehci_root_hub.
1739 		    rh_client_intr_reqp->intr_len;
1740 
1741 		curr_intr_reqp = usba_hcdi_dup_intr_req(ph->p_dip,
1742 		    ehcip->ehci_root_hub.rh_client_intr_reqp,
1743 		    length, flags);
1744 
1745 		if (curr_intr_reqp == NULL) {
1746 
1747 			USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
1748 			    "ehci_root_hub_allocate_intr_pipe_resource:"
1749 			    "Interrupt request structure allocation failed");
1750 
1751 			return (USB_NO_RESOURCES);
1752 		}
1753 
1754 		ehcip->ehci_root_hub.rh_curr_intr_reqp = curr_intr_reqp;
1755 		mutex_enter(&ph->p_mutex);
1756 		ph->p_req_count++;
1757 		mutex_exit(&ph->p_mutex);
1758 	}
1759 
1760 	/* Start the timer for the root hub interrupt pipe polling */
1761 	if (ehcip->ehci_root_hub.rh_intr_pipe_timer_id == 0) {
1762 		ehcip->ehci_root_hub.rh_intr_pipe_timer_id =
1763 		    timeout(ehci_handle_root_hub_status_change,
1764 		    (void *)ehcip, drv_usectohz(EHCI_RH_POLL_TIME));
1765 
1766 		ehcip->ehci_root_hub.
1767 		    rh_intr_pipe_state = EHCI_PIPE_STATE_ACTIVE;
1768 	}
1769 
1770 	return (USB_SUCCESS);
1771 }
1772 
1773 
1774 /*
1775  * ehci_root_hub_intr_pipe_cleanup:
1776  *
1777  * Deallocate all interrupt requests and do callback
1778  * the original client interrupt request.
1779  */
1780 static void
ehci_root_hub_intr_pipe_cleanup(ehci_state_t * ehcip,usb_cr_t completion_reason)1781 ehci_root_hub_intr_pipe_cleanup(
1782 	ehci_state_t		*ehcip,
1783 	usb_cr_t		completion_reason)
1784 {
1785 	usb_intr_req_t		*curr_intr_reqp;
1786 	usb_opaque_t		client_intr_reqp;
1787 	timeout_id_t		timer_id;
1788 	usba_pipe_handle_data_t	*ph;
1789 
1790 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
1791 	    "ehci_root_hub_intr_pipe_cleanup");
1792 
1793 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
1794 
1795 	/* Get the interrupt pipe handle */
1796 	ph = ehcip->ehci_root_hub.rh_intr_pipe_handle;
1797 
1798 	/* Get the interrupt timerid */
1799 	timer_id = ehcip->ehci_root_hub.rh_intr_pipe_timer_id;
1800 
1801 	/* Stop the root hub interrupt timer */
1802 	if (timer_id) {
1803 		/* Reset the timer id to zero */
1804 		ehcip->ehci_root_hub.rh_intr_pipe_timer_id = 0;
1805 
1806 		mutex_exit(&ehcip->ehci_int_mutex);
1807 		(void) untimeout(timer_id);
1808 		mutex_enter(&ehcip->ehci_int_mutex);
1809 	}
1810 
1811 	/* Reset the current interrupt request pointer */
1812 	curr_intr_reqp = ehcip->ehci_root_hub.rh_curr_intr_reqp;
1813 
1814 	/* Deallocate uncompleted interrupt request */
1815 	if (curr_intr_reqp) {
1816 		ehcip->ehci_root_hub.rh_curr_intr_reqp = NULL;
1817 		usb_free_intr_req(curr_intr_reqp);
1818 
1819 		mutex_enter(&ph->p_mutex);
1820 		ph->p_req_count--;
1821 		mutex_exit(&ph->p_mutex);
1822 	}
1823 
1824 	client_intr_reqp = (usb_opaque_t)
1825 	    ehcip->ehci_root_hub.rh_client_intr_reqp;
1826 
1827 	/* Callback for original client interrupt request */
1828 	if (client_intr_reqp) {
1829 		ehci_root_hub_hcdi_callback(ph, completion_reason);
1830 	}
1831 }
1832 
1833 
1834 /*
1835  * ehci_handle_root_hub_status_change:
1836  *
1837  * A root hub status change interrupt will occur any time there is a change
1838  * in the root hub status register or one of the port status registers.
1839  */
1840 static void
ehci_handle_root_hub_status_change(void * arg)1841 ehci_handle_root_hub_status_change(void *arg)
1842 {
1843 	ehci_state_t		*ehcip = (ehci_state_t *)arg;
1844 	usb_hub_descr_t		*root_hub_descr =
1845 	    &ehcip->ehci_root_hub.rh_descr;
1846 	usb_intr_req_t		*curr_intr_reqp;
1847 	usb_port_mask_t		port_mask = 0;
1848 	uint_t			new_port_status;
1849 	uint_t			change_status;
1850 	uint_t			port_status;
1851 	mblk_t			*message;
1852 	size_t			length;
1853 	usb_ep_descr_t		*eptd;
1854 	usba_pipe_handle_data_t	*ph;
1855 	int			i;
1856 
1857 	mutex_enter(&ehcip->ehci_int_mutex);
1858 
1859 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
1860 	    "ehci_handle_root_hub_status_change: state = %d",
1861 	    ehcip->ehci_root_hub.rh_intr_pipe_state);
1862 
1863 #if defined(__x86)
1864 	/*
1865 	 * When ohci are attached in ferrari 4000, SMI will reset ehci
1866 	 * registers. If ehci registers have been reset, we must re-initialize
1867 	 * them. During booting, this function will be called 2~3 times. When
1868 	 * this function is called 16 times, ohci drivers have been attached
1869 	 * and stop checking the ehci registers.
1870 	 */
1871 	if (ehcip->ehci_polled_root_hub_count < 16) {
1872 
1873 		if (Get_OpReg(ehci_config_flag) == 0) {
1874 
1875 			USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB,
1876 			    ehcip->ehci_log_hdl,
1877 			    "ehci_handle_root_hub_status_change:"
1878 			    " EHCI have been reset");
1879 
1880 			/* Reinitialize the controller */
1881 			if (ehci_init_ctlr(ehcip, EHCI_REINITIALIZATION) !=
1882 			    DDI_SUCCESS) {
1883 				mutex_exit(&ehcip->ehci_int_mutex);
1884 
1885 				return;
1886 			}
1887 		}
1888 
1889 		ehcip->ehci_polled_root_hub_count++;
1890 	}
1891 #endif	/* __x86 */
1892 
1893 	/* Get the current interrupt request pointer */
1894 	curr_intr_reqp = ehcip->ehci_root_hub.rh_curr_intr_reqp;
1895 
1896 	ph = ehcip->ehci_root_hub.rh_intr_pipe_handle;
1897 
1898 	/* Check whether timeout handler is valid */
1899 	if (ehcip->ehci_root_hub.rh_intr_pipe_timer_id) {
1900 		/* Check host controller is in operational state */
1901 		if ((ehci_state_is_operational(ehcip)) != USB_SUCCESS) {
1902 			/* Reset the timer id */
1903 			ehcip->ehci_root_hub.rh_intr_pipe_timer_id = 0;
1904 
1905 			/* Do interrupt pipe cleanup */
1906 			ehci_root_hub_intr_pipe_cleanup(
1907 			    ehcip, USB_CR_HC_HARDWARE_ERR);
1908 
1909 			mutex_exit(&ehcip->ehci_int_mutex);
1910 
1911 			return;
1912 		}
1913 	} else {
1914 		mutex_exit(&ehcip->ehci_int_mutex);
1915 
1916 		return;
1917 	}
1918 
1919 	eptd = &ehcip->ehci_root_hub.rh_intr_pipe_handle->p_ep;
1920 
1921 	/* Check each port */
1922 	for (i = 0; i < root_hub_descr->bNbrPorts; i++) {
1923 
1924 		port_status = ehci_get_root_hub_port_status(ehcip, i);
1925 
1926 		new_port_status = port_status & PORT_STATUS_MASK;
1927 		change_status = (port_status >> 16) & PORT_CHANGE_MASK;
1928 
1929 		/*
1930 		 * If there is change in the port status then set the bit in the
1931 		 * bitmap of changes and inform hub driver about these changes.
1932 		 * Hub driver will take care of these changes.
1933 		 */
1934 		if (change_status) {
1935 
1936 			/* See if a device was attached/detached */
1937 			if (change_status & PORT_CHANGE_CSC) {
1938 				/*
1939 				 * Update the state depending on whether
1940 				 * the port was attached or detached.
1941 				 */
1942 				if (new_port_status & PORT_STATUS_CCS) {
1943 					ehcip->ehci_root_hub.
1944 					    rh_port_state[i] = DISABLED;
1945 
1946 					USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB,
1947 					    ehcip->ehci_log_hdl,
1948 					    "Port %d connected", i+1);
1949 				} else {
1950 					ehcip->ehci_root_hub.
1951 					    rh_port_state[i] = DISCONNECTED;
1952 
1953 					USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB,
1954 					    ehcip->ehci_log_hdl,
1955 					    "Port %d disconnected", i+1);
1956 				}
1957 			}
1958 
1959 			/* See if port enable status changed */
1960 			if (change_status & PORT_CHANGE_PESC) {
1961 				/*
1962 				 * Update the state depending on whether
1963 				 * the port was enabled or disabled.
1964 				 */
1965 				if (new_port_status & PORT_STATUS_PES) {
1966 					ehcip->ehci_root_hub.
1967 					    rh_port_state[i] = ENABLED;
1968 
1969 					USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB,
1970 					    ehcip->ehci_log_hdl,
1971 					    "Port %d enabled", i+1);
1972 				} else {
1973 					ehcip->ehci_root_hub.
1974 					    rh_port_state[i] = DISABLED;
1975 
1976 					USB_DPRINTF_L3(PRINT_MASK_ROOT_HUB,
1977 					    ehcip->ehci_log_hdl,
1978 					    "Port %d disabled", i+1);
1979 				}
1980 			}
1981 
1982 			port_mask |= 1 << (i + 1);
1983 
1984 			/* Update the status */
1985 			ehcip->ehci_root_hub.
1986 			    rh_port_status[i] = new_port_status;
1987 		}
1988 	}
1989 
1990 	if (ph && port_mask && curr_intr_reqp) {
1991 		length = eptd->wMaxPacketSize;
1992 
1993 		ASSERT(length != 0);
1994 
1995 		/* Get the  message block */
1996 		message = curr_intr_reqp->intr_data;
1997 
1998 		ASSERT(message != NULL);
1999 
2000 		do {
2001 			/*
2002 			 * check that the mblk is big enough when we
2003 			 * are writing bytes into it
2004 			 */
2005 			if (message->b_wptr >= message->b_datap->db_lim) {
2006 
2007 				USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB,
2008 				    ehcip->ehci_log_hdl,
2009 				    "ehci_handle_root_hub_status_change"
2010 				    "mblk data overflow.");
2011 
2012 				break;
2013 			}
2014 			*message->b_wptr++ = (uchar_t)port_mask;
2015 			port_mask >>= 8;
2016 		} while (port_mask != 0);
2017 
2018 		ehci_root_hub_hcdi_callback(ph, USB_CR_OK);
2019 	}
2020 
2021 	/* Reset the timer id */
2022 	ehcip->ehci_root_hub.rh_intr_pipe_timer_id = 0;
2023 
2024 	if (ehcip->ehci_root_hub.rh_intr_pipe_state ==
2025 	    EHCI_PIPE_STATE_ACTIVE) {
2026 		/*
2027 		 * If needed, allocate new interrupt request. Also
2028 		 * start the timer for the root hub interrupt polling.
2029 		 */
2030 		if ((ehci_root_hub_allocate_intr_pipe_resource(
2031 		    ehcip, 0)) != USB_SUCCESS) {
2032 
2033 			USB_DPRINTF_L2(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
2034 			    "ehci_handle_root_hub_status_change: No Resources");
2035 
2036 			/* Do interrupt pipe cleanup */
2037 			ehci_root_hub_intr_pipe_cleanup(
2038 			    ehcip, USB_CR_NO_RESOURCES);
2039 		}
2040 	}
2041 
2042 	mutex_exit(&ehcip->ehci_int_mutex);
2043 }
2044 
2045 
2046 /*
2047  * ehci_root_hub_hcdi_callback()
2048  *
2049  * Convenience wrapper around usba_hcdi_cb() for the root hub.
2050  */
2051 static void
ehci_root_hub_hcdi_callback(usba_pipe_handle_data_t * ph,usb_cr_t completion_reason)2052 ehci_root_hub_hcdi_callback(
2053 	usba_pipe_handle_data_t	*ph,
2054 	usb_cr_t		completion_reason)
2055 {
2056 	ehci_state_t		*ehcip = ehci_obtain_state(
2057 	    ph->p_usba_device->usb_root_hub_dip);
2058 	uchar_t			attributes = ph->p_ep.bmAttributes &
2059 	    USB_EP_ATTR_MASK;
2060 	usb_opaque_t		curr_xfer_reqp;
2061 	uint_t			pipe_state = 0;
2062 
2063 	USB_DPRINTF_L4(PRINT_MASK_ROOT_HUB, ehcip->ehci_log_hdl,
2064 	    "ehci_root_hub_hcdi_callback: ph = 0x%p, cr = 0x%x",
2065 	    (void *)ph, completion_reason);
2066 
2067 	ASSERT(mutex_owned(&ehcip->ehci_int_mutex));
2068 
2069 	/* Set the pipe state as per completion reason */
2070 	switch (completion_reason) {
2071 	case USB_CR_OK:
2072 		switch (attributes) {
2073 		case USB_EP_ATTR_CONTROL:
2074 			pipe_state = EHCI_PIPE_STATE_IDLE;
2075 			break;
2076 		case USB_EP_ATTR_INTR:
2077 			pipe_state = ehcip->ehci_root_hub.
2078 			    rh_intr_pipe_state;
2079 			break;
2080 		}
2081 		break;
2082 	case USB_CR_NO_RESOURCES:
2083 	case USB_CR_NOT_SUPPORTED:
2084 	case USB_CR_STOPPED_POLLING:
2085 	case USB_CR_PIPE_RESET:
2086 	case USB_CR_HC_HARDWARE_ERR:
2087 		/* Set pipe state to idle */
2088 		pipe_state = EHCI_PIPE_STATE_IDLE;
2089 		break;
2090 	case USB_CR_PIPE_CLOSING:
2091 		break;
2092 	default:
2093 		/* Set pipe state to error */
2094 		pipe_state = EHCI_PIPE_STATE_ERROR;
2095 		break;
2096 	}
2097 
2098 	switch (attributes) {
2099 	case USB_EP_ATTR_CONTROL:
2100 		curr_xfer_reqp = (usb_opaque_t)
2101 		    ehcip->ehci_root_hub.rh_curr_ctrl_reqp;
2102 
2103 		ehcip->ehci_root_hub.rh_curr_ctrl_reqp = NULL;
2104 		ehcip->ehci_root_hub.rh_ctrl_pipe_state = pipe_state;
2105 		break;
2106 	case USB_EP_ATTR_INTR:
2107 		/* if curr_intr_reqp available then use this request */
2108 		if (ehcip->ehci_root_hub.rh_curr_intr_reqp) {
2109 			curr_xfer_reqp = (usb_opaque_t)ehcip->
2110 			    ehci_root_hub.rh_curr_intr_reqp;
2111 
2112 			ehcip->ehci_root_hub.rh_curr_intr_reqp = NULL;
2113 		} else {
2114 			/* no current request, use client's request */
2115 			curr_xfer_reqp = (usb_opaque_t)
2116 			    ehcip->ehci_root_hub.rh_client_intr_reqp;
2117 
2118 			ehcip->ehci_root_hub.rh_client_intr_reqp = NULL;
2119 		}
2120 		ehcip->ehci_root_hub.rh_intr_pipe_state = pipe_state;
2121 		break;
2122 	}
2123 
2124 	ASSERT(curr_xfer_reqp != NULL);
2125 
2126 	mutex_exit(&ehcip->ehci_int_mutex);
2127 	usba_hcdi_cb(ph, curr_xfer_reqp, completion_reason);
2128 	mutex_enter(&ehcip->ehci_int_mutex);
2129 }
2130