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