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