xref: /illumos-gate/usr/src/uts/common/io/usb/hcd/uhci/uhci.c (revision 4fceebdf03eeac0d7c58a4f70cc19b00a8c40a73)
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 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 /*
29  * Universal Host Controller Driver (UHCI)
30  *
31  * The UHCI driver is a driver which interfaces to the Universal
32  * Serial Bus Architecture (USBA) and the Host Controller (HC). The interface to
33  * the Host Controller is defined by the Universal Host Controller Interface.
34  * This file contains code for auto-configuration entry points and interrupt
35  * handling.
36  */
37 #include <sys/usb/hcd/uhci/uhcid.h>
38 #include <sys/usb/hcd/uhci/uhcihub.h>
39 #include <sys/usb/hcd/uhci/uhciutil.h>
40 
41 /*
42  * Prototype Declarations for cb_ops and dev_ops
43  */
44 static	int uhci_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
45 static  int uhci_add_intrs(uhci_state_t *uhcip, int	intr_type);
46 static	int uhci_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
47 static void uhci_rem_intrs(uhci_state_t	*uhcip);
48 static	int uhci_open(dev_t *devp, int flags, int otyp, cred_t *credp);
49 static	int uhci_close(dev_t dev, int flag, int otyp, cred_t *credp);
50 static	int uhci_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
51 		cred_t *credp, int *rvalp);
52 static	int uhci_reset(dev_info_t *dip, ddi_reset_cmd_t cmd);
53 static	int uhci_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
54 		void **result);
55 
56 static struct cb_ops uhci_cb_ops = {
57 	uhci_open,			/* Open */
58 	uhci_close,			/* Close */
59 	nodev,				/* Strategy */
60 	nodev,				/* Print */
61 	nodev,				/* Dump */
62 	nodev,				/* Read */
63 	nodev,				/* Write */
64 	uhci_ioctl,			/* Ioctl */
65 	nodev,				/* Devmap */
66 	nodev,				/* Mmap */
67 	nodev,				/* Segmap */
68 	nochpoll,			/* Poll */
69 	ddi_prop_op,			/* cb_prop_op */
70 	NULL,				/* Streamtab */
71 	D_MP				/* Driver compatibility flag */
72 };
73 
74 static struct dev_ops uhci_ops = {
75 	DEVO_REV,			/* Devo_rev */
76 	0,				/* Refcnt */
77 	uhci_info,			/* Info */
78 	nulldev,			/* Identify */
79 	nulldev,			/* Probe */
80 	uhci_attach,			/* Attach */
81 	uhci_detach,			/* Detach */
82 	uhci_reset,			/* Reset */
83 	&uhci_cb_ops,			/* Driver operations */
84 	&usba_hubdi_busops,		/* Bus operations */
85 	NULL				/* Power */
86 };
87 
88 static struct modldrv modldrv = {
89 	&mod_driverops,		/* Type of module. This one is a driver */
90 	"USB UHCI Controller Driver %I%",	/* Name of the module. */
91 	&uhci_ops,		/* Driver ops */
92 };
93 
94 static struct modlinkage modlinkage = {
95 	MODREV_1, (void *)&modldrv, NULL
96 };
97 
98 /*
99  *  Globals
100  */
101 void		*uhci_statep;
102 uint_t		uhci_errlevel = USB_LOG_L2;
103 uint_t		uhci_errmask = PRINT_MASK_ALL;
104 uint_t		uhci_instance_debug = (uint_t)-1;
105 
106 uint_t		uhci_td_pool_size = 256;			/* Num TDs */
107 uint_t		uhci_qh_pool_size = 130;			/* Num QHs */
108 ushort_t	uhci_tree_bottom_nodes[NUM_FRAME_LST_ENTRIES];
109 
110 
111 /*
112  * UHCI MSI tunable:
113  *
114  * By default MSI is enabled on all supported platforms.
115  */
116 boolean_t uhci_enable_msi = B_TRUE;
117 
118 /*
119  * tunable, delay during attach in seconds
120  */
121 int 		uhci_attach_wait = 1;
122 
123 /* function prototypes */
124 static void	uhci_handle_intr_td_errors(uhci_state_t *uhcip, uhci_td_t *td,
125 			uhci_trans_wrapper_t *tw, uhci_pipe_private_t *pp);
126 static void	uhci_handle_one_xfer_completion(uhci_state_t *uhcip,
127 			usb_cr_t usb_err, uhci_td_t *td);
128 static uint_t	uhci_intr(caddr_t arg1, caddr_t arg2);
129 static int	uhci_cleanup(uhci_state_t *uhcip);
130 
131 
132 int
133 _init(void)
134 {
135 	int error;
136 	ushort_t i, j, k, *temp, num_of_nodes;
137 
138 	/* Initialize the soft state structures */
139 	if ((error = ddi_soft_state_init(&uhci_statep, sizeof (uhci_state_t),
140 	    UHCI_MAX_INSTS)) != 0) {
141 
142 		return (error);
143 	}
144 
145 	/* Install the loadable module */
146 	if ((error = mod_install(&modlinkage)) != 0) {
147 		ddi_soft_state_fini(&uhci_statep);
148 
149 		return (error);
150 	}
151 
152 	/*
153 	 *  Build the tree bottom shared by all instances
154 	 */
155 	temp = kmem_zalloc(NUM_FRAME_LST_ENTRIES * 2, KM_SLEEP);
156 
157 	num_of_nodes = 1;
158 	for (i = 0; i < log_2(NUM_FRAME_LST_ENTRIES); i++) {
159 		for (j = 0, k = 0; k < num_of_nodes; k++, j++) {
160 			uhci_tree_bottom_nodes[j++] = temp[k];
161 			uhci_tree_bottom_nodes[j]   = temp[k] + pow_2(i);
162 		}
163 
164 		num_of_nodes *= 2;
165 		for (k = 0; k < num_of_nodes; k++)
166 			temp[k] = uhci_tree_bottom_nodes[k];
167 
168 	}
169 	kmem_free(temp, (NUM_FRAME_LST_ENTRIES*2));
170 
171 
172 	return (error);
173 }
174 
175 
176 int
177 _info(struct modinfo *modinfop)
178 {
179 	return (mod_info(&modlinkage, modinfop));
180 }
181 
182 
183 int
184 _fini(void)
185 {
186 	int error;
187 
188 	error = mod_remove(&modlinkage);
189 
190 	if (error == 0) {
191 		/* Release per module resources */
192 		ddi_soft_state_fini(&uhci_statep);
193 	}
194 
195 	return (error);
196 }
197 
198 /*
199  * The following simulated polling is for debugging purposes only.
200  * It is activated on x86 by setting usb-polling=true in GRUB or uhci.conf.
201  */
202 static int
203 uhci_is_polled(dev_info_t *dip)
204 {
205 	int ret;
206 	char *propval;
207 
208 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, 0,
209 	    "usb-polling", &propval) != DDI_SUCCESS)
210 
211 		return (0);
212 
213 	ret = (strcmp(propval, "true") == 0);
214 	ddi_prop_free(propval);
215 
216 	return (ret);
217 }
218 
219 static void
220 uhci_poll_intr(void *arg)
221 {
222 	/* poll every msec */
223 	for (;;) {
224 		(void) uhci_intr(arg, NULL);
225 		delay(drv_usectohz(1000));
226 	}
227 }
228 
229 /*
230  * Host Controller Driver (HCD) Auto configuration entry points
231  */
232 
233 /*
234  * Function Name  :  uhci_attach:
235  * Description	  :  Attach entry point - called by the Kernel.
236  *		     Allocates of per controller data structure.
237  *		     Initializes the controller.
238  * Output	  :  DDI_SUCCESS / DDI_FAILURE
239  */
240 static int
241 uhci_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
242 {
243 	int				instance, polled;
244 	int				i, intr_types;
245 	uhci_state_t			*uhcip = NULL;
246 	usba_hcdi_register_args_t	hcdi_args;
247 
248 	USB_DPRINTF_L4(PRINT_MASK_ATTA, NULL, "uhci_attach:");
249 
250 	switch (cmd) {
251 	case DDI_ATTACH:
252 		break;
253 	case DDI_RESUME:
254 	default:
255 
256 		return (DDI_FAILURE);
257 	}
258 
259 
260 	/* Get the instance and create soft state */
261 	instance = ddi_get_instance(dip);
262 
263 	/* Allocate the soft state structure for this instance of the driver */
264 	if (ddi_soft_state_zalloc(uhci_statep, instance) != 0) {
265 
266 		return (DDI_FAILURE);
267 	}
268 
269 	if ((uhcip = ddi_get_soft_state(uhci_statep, instance)) == NULL) {
270 
271 		return (DDI_FAILURE);
272 	}
273 
274 	uhcip->uhci_log_hdl = usb_alloc_log_hdl(dip, "uhci", &uhci_errlevel,
275 	    &uhci_errmask, &uhci_instance_debug, 0);
276 
277 	/* Save the dip and instance */
278 	uhcip->uhci_dip		= dip;
279 	uhcip->uhci_instance	= instance;
280 
281 	polled = uhci_is_polled(dip);
282 	if (polled)
283 
284 		goto skip_intr;
285 
286 	/* Get supported interrupt types */
287 	if (ddi_intr_get_supported_types(uhcip->uhci_dip,
288 	    &intr_types) != DDI_SUCCESS) {
289 		USB_DPRINTF_L2(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
290 		    "uhci_attach: ddi_intr_get_supported_types failed");
291 
292 		usb_free_log_hdl(uhcip->uhci_log_hdl);
293 		ddi_soft_state_free(uhci_statep, instance);
294 
295 		return (DDI_FAILURE);
296 	}
297 
298 	USB_DPRINTF_L3(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
299 	    "uhci_attach: supported interrupt types 0x%x", intr_types);
300 
301 	if ((intr_types & DDI_INTR_TYPE_MSI) && uhci_enable_msi) {
302 		if (uhci_add_intrs(uhcip, DDI_INTR_TYPE_MSI)
303 		    != DDI_SUCCESS) {
304 			USB_DPRINTF_L4(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
305 			    "uhci_attach: MSI registration failed, "
306 			    "trying FIXED interrupt \n");
307 		} else {
308 			USB_DPRINTF_L4(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
309 			    "uhci_attach: Using MSI interrupt type\n");
310 
311 			uhcip->uhci_intr_type = DDI_INTR_TYPE_MSI;
312 		}
313 	}
314 
315 	if (!(uhcip->uhci_htable) && (intr_types & DDI_INTR_TYPE_FIXED)) {
316 		if (uhci_add_intrs(uhcip, DDI_INTR_TYPE_FIXED)
317 		    != DDI_SUCCESS) {
318 			USB_DPRINTF_L2(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
319 			    "uhci_attach: FIXED interrupt registration "
320 			    "failed\n");
321 
322 			usb_free_log_hdl(uhcip->uhci_log_hdl);
323 			ddi_soft_state_free(uhci_statep, instance);
324 
325 			return (DDI_FAILURE);
326 		}
327 
328 		USB_DPRINTF_L4(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
329 		    "uhci_attach: Using FIXED interrupt type\n");
330 
331 		uhcip->uhci_intr_type = DDI_INTR_TYPE_FIXED;
332 	}
333 
334 skip_intr:
335 	/* Semaphore to serialize opens and closes */
336 	sema_init(&uhcip->uhci_ocsem, 1, NULL, SEMA_DRIVER, NULL);
337 
338 	/* Create prototype condition variable */
339 	cv_init(&uhcip->uhci_cv_SOF, NULL, CV_DRIVER, NULL);
340 
341 	/* Initialize the DMA attributes */
342 	uhci_set_dma_attributes(uhcip);
343 
344 	/* Initialize the kstat structures */
345 	uhci_create_stats(uhcip);
346 
347 	/* Create the td and ed pools */
348 	if (uhci_allocate_pools(uhcip) != USB_SUCCESS) {
349 
350 		goto fail;
351 	}
352 
353 	/* Map the registers */
354 	if (uhci_map_regs(uhcip) != USB_SUCCESS) {
355 
356 		goto fail;
357 	}
358 
359 	/* Set the flag that uhci controller has not been initialized. */
360 	uhcip->uhci_ctlr_init_flag = B_FALSE;
361 
362 	/* Enable all interrupts */
363 	if (polled) {
364 		extern pri_t maxclsyspri;
365 
366 		USB_DPRINTF_L2(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
367 		    "uhci_attach: running in simulated polled mode.");
368 
369 		/* create thread to poll */
370 		(void) thread_create(NULL, 0, uhci_poll_intr, uhcip, 0, &p0,
371 		    TS_RUN, maxclsyspri);
372 	} else if (uhcip->uhci_intr_cap & DDI_INTR_FLAG_BLOCK) {
373 		/* Call ddi_intr_block_enable() for MSI interrupts */
374 		(void) ddi_intr_block_enable(uhcip->uhci_htable,
375 		    uhcip->uhci_intr_cnt);
376 	} else {
377 		/* Call ddi_intr_enable for MSI or FIXED interrupts */
378 		for (i = 0; i < uhcip->uhci_intr_cnt; i++)
379 			(void) ddi_intr_enable(uhcip->uhci_htable[i]);
380 	}
381 
382 
383 	/* Initialize the controller */
384 	if (uhci_init_ctlr(uhcip) != USB_SUCCESS) {
385 
386 		goto fail;
387 	}
388 
389 	/*
390 	 * At this point, the hardware will be okay.
391 	 * Initialize the usba_hcdi structure
392 	 */
393 	uhcip->uhci_hcdi_ops = uhci_alloc_hcdi_ops(uhcip);
394 
395 	/*
396 	 * Make this HCD instance known to USBA
397 	 * (dma_attr must be passed for USBA busctl's)
398 	 */
399 	hcdi_args.usba_hcdi_register_version = HCDI_REGISTER_VERSION;
400 	hcdi_args.usba_hcdi_register_dip = dip;
401 	hcdi_args.usba_hcdi_register_ops = uhcip->uhci_hcdi_ops;
402 	hcdi_args.usba_hcdi_register_dma_attr = &uhcip->uhci_dma_attr;
403 	hcdi_args.usba_hcdi_register_iblock_cookie =
404 	    (ddi_iblock_cookie_t)(uintptr_t)uhcip->uhci_intr_pri;
405 
406 	if (usba_hcdi_register(&hcdi_args, 0) != USB_SUCCESS) {
407 
408 		goto fail;
409 	}
410 
411 #ifndef __sparc
412 	/*
413 	 * On NCR system,  the driver seen  failure of some commands
414 	 * while booting. This delay mysteriously solved the problem.
415 	 */
416 	delay(drv_usectohz(uhci_attach_wait*1000000));
417 #endif
418 
419 	/*
420 	 * Create another timeout handler to check whether any
421 	 * control/bulk/interrupt commands failed.
422 	 * This gets called every second.
423 	 */
424 	uhcip->uhci_cmd_timeout_id = timeout(uhci_cmd_timeout_hdlr,
425 					(void *)uhcip, UHCI_ONE_SECOND);
426 
427 	mutex_enter(&uhcip->uhci_int_mutex);
428 
429 	/*
430 	 * Set HcInterruptEnable to enable all interrupts except Root
431 	 * Hub Status change and SOF interrupts.
432 	 */
433 	Set_OpReg16(USBINTR, ENABLE_ALL_INTRS);
434 
435 	/* Test the SOF interrupt */
436 	if (uhci_wait_for_sof(uhcip) != USB_SUCCESS) {
437 		USB_DPRINTF_L0(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
438 		    "No SOF interrupts have been received, this USB UHCI host"
439 		    " controller is unusable");
440 		mutex_exit(&uhcip->uhci_int_mutex);
441 
442 		goto fail;
443 	}
444 
445 	mutex_exit(&uhcip->uhci_int_mutex);
446 
447 	/* This should be the last step which might fail during attaching */
448 	if (uhci_init_root_hub(uhcip) != USB_SUCCESS) {
449 
450 		goto fail;
451 	}
452 
453 	/* Display information in the banner */
454 	ddi_report_dev(dip);
455 
456 	USB_DPRINTF_L4(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
457 	    "uhci_attach successful");
458 
459 	return (DDI_SUCCESS);
460 
461 fail:
462 	USB_DPRINTF_L2(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
463 	    "failed to attach");
464 
465 	(void) uhci_cleanup(uhcip);
466 
467 	return (DDI_FAILURE);
468 }
469 
470 
471 /*
472  * uhci_add_intrs:
473  *
474  * Register FIXED or MSI interrupts.
475  */
476 static int
477 uhci_add_intrs(uhci_state_t	*uhcip,
478 		int		intr_type)
479 {
480 	int	actual, avail, intr_size, count = 0;
481 	int 	i, flag, ret;
482 
483 	USB_DPRINTF_L4(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
484 	    "uhci_add_intrs: interrupt type 0x%x", intr_type);
485 
486 	/* Get number of interrupts */
487 	ret = ddi_intr_get_nintrs(uhcip->uhci_dip, intr_type, &count);
488 	if ((ret != DDI_SUCCESS) || (count == 0)) {
489 		USB_DPRINTF_L2(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
490 		    "uhci_add_intrs: ddi_intr_get_nintrs() failure, "
491 		    "ret: %d, count: %d", ret, count);
492 
493 		return (DDI_FAILURE);
494 	}
495 
496 	/* Get number of available interrupts */
497 	ret = ddi_intr_get_navail(uhcip->uhci_dip, intr_type, &avail);
498 	if ((ret != DDI_SUCCESS) || (avail == 0)) {
499 		USB_DPRINTF_L2(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
500 		    "uhci_add_intrs: ddi_intr_get_navail() failure, "
501 		    "ret: %d, count: %d", ret, count);
502 
503 		return (DDI_FAILURE);
504 	}
505 
506 	if (avail < count) {
507 		USB_DPRINTF_L3(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
508 		    "uhci_add_intrs: uhci_add_intrs: nintrs () "
509 		    "returned %d, navail returned %d\n", count, avail);
510 	}
511 
512 	/* Allocate an array of interrupt handles */
513 	intr_size = count * sizeof (ddi_intr_handle_t);
514 	uhcip->uhci_htable = kmem_zalloc(intr_size, KM_SLEEP);
515 
516 	flag = (intr_type == DDI_INTR_TYPE_MSI) ?
517 	    DDI_INTR_ALLOC_STRICT:DDI_INTR_ALLOC_NORMAL;
518 
519 	/* call ddi_intr_alloc() */
520 	ret = ddi_intr_alloc(uhcip->uhci_dip, uhcip->uhci_htable,
521 	    intr_type, 0, count, &actual, flag);
522 
523 	if ((ret != DDI_SUCCESS) || (actual == 0)) {
524 		USB_DPRINTF_L2(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
525 		    "uhci_add_intrs: ddi_intr_alloc() failed %d", ret);
526 
527 		kmem_free(uhcip->uhci_htable, intr_size);
528 
529 		return (DDI_FAILURE);
530 	}
531 
532 	if (actual < count) {
533 		USB_DPRINTF_L3(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
534 		    "uhci_add_intrs: Requested: %d, Received: %d\n",
535 		    count, actual);
536 
537 		for (i = 0; i < actual; i++)
538 			(void) ddi_intr_free(uhcip->uhci_htable[i]);
539 
540 		kmem_free(uhcip->uhci_htable, intr_size);
541 
542 		return (DDI_FAILURE);
543 	}
544 
545 	uhcip->uhci_intr_cnt = actual;
546 
547 	if ((ret = ddi_intr_get_pri(uhcip->uhci_htable[0],
548 	    &uhcip->uhci_intr_pri)) != DDI_SUCCESS) {
549 		USB_DPRINTF_L2(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
550 		    "uhci_add_intrs: ddi_intr_get_pri() failed %d", ret);
551 
552 		for (i = 0; i < actual; i++)
553 			(void) ddi_intr_free(uhcip->uhci_htable[i]);
554 
555 		kmem_free(uhcip->uhci_htable, intr_size);
556 
557 		return (DDI_FAILURE);
558 	}
559 
560 	USB_DPRINTF_L3(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
561 	    "uhci_add_intrs: Supported Interrupt priority 0x%x",
562 	    uhcip->uhci_intr_pri);
563 
564 	/* Test for high level mutex */
565 	if (uhcip->uhci_intr_pri >= ddi_intr_get_hilevel_pri()) {
566 		USB_DPRINTF_L2(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
567 		    "uhci_add_intrs: Hi level interrupt not supported");
568 
569 		for (i = 0; i < actual; i++)
570 			(void) ddi_intr_free(uhcip->uhci_htable[i]);
571 
572 		kmem_free(uhcip->uhci_htable, intr_size);
573 
574 		return (DDI_FAILURE);
575 	}
576 
577 	/* Initialize the mutex */
578 	mutex_init(&uhcip->uhci_int_mutex, NULL, MUTEX_DRIVER,
579 	    DDI_INTR_PRI(uhcip->uhci_intr_pri));
580 
581 	/* Call ddi_intr_add_handler() */
582 	for (i = 0; i < actual; i++) {
583 		if ((ret = ddi_intr_add_handler(uhcip->uhci_htable[i],
584 		    uhci_intr, (caddr_t)uhcip,
585 		    (caddr_t)(uintptr_t)i)) != DDI_SUCCESS) {
586 			USB_DPRINTF_L2(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
587 			    "uhci_add_intrs: ddi_intr_add_handler() "
588 			    "failed %d", ret);
589 
590 			for (i = 0; i < actual; i++)
591 				(void) ddi_intr_free(uhcip->uhci_htable[i]);
592 
593 			mutex_destroy(&uhcip->uhci_int_mutex);
594 			kmem_free(uhcip->uhci_htable, intr_size);
595 
596 			return (DDI_FAILURE);
597 		}
598 	}
599 
600 	if ((ret = ddi_intr_get_cap(uhcip->uhci_htable[0],
601 	    &uhcip->uhci_intr_cap)) != DDI_SUCCESS) {
602 		USB_DPRINTF_L2(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
603 		    "uhci_add_intrs: ddi_intr_get_cap() failed %d", ret);
604 
605 		for (i = 0; i < actual; i++) {
606 			(void) ddi_intr_remove_handler(uhcip->uhci_htable[i]);
607 			(void) ddi_intr_free(uhcip->uhci_htable[i]);
608 		}
609 
610 		mutex_destroy(&uhcip->uhci_int_mutex);
611 		kmem_free(uhcip->uhci_htable, intr_size);
612 
613 		return (DDI_FAILURE);
614 	}
615 
616 	return (DDI_SUCCESS);
617 }
618 
619 
620 /*
621  * Function Name:	uhci_detach
622  * Description:		Detach entry point - called by the Kernel.
623  *			Deallocates all the memory
624  *			Unregisters the interrupt handle and other resources.
625  * Output:		DDI_SUCCESS / DDI_FAILURE
626  */
627 static int
628 uhci_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
629 {
630 	uhci_state_t	*uhcip = uhci_obtain_state(dip);
631 
632 	USB_DPRINTF_L4(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
633 	    "uhci_detach:");
634 
635 	switch (cmd) {
636 	case DDI_DETACH:
637 
638 		return (uhci_cleanup(uhcip) == USB_SUCCESS ?
639 					DDI_SUCCESS : DDI_FAILURE);
640 	case DDI_SUSPEND:
641 		USB_DPRINTF_L2(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
642 		    "uhci_detach: Suspend not supported");
643 
644 		return (DDI_FAILURE);
645 	default:
646 
647 		return (DDI_FAILURE);
648 	}
649 }
650 
651 
652 /*
653  * uhci_rem_intrs:
654  *
655  * Unregister FIXED or MSI interrupts
656  */
657 static void
658 uhci_rem_intrs(uhci_state_t	*uhcip)
659 {
660 	int	i;
661 
662 	USB_DPRINTF_L4(PRINT_MASK_ATTA, uhcip->uhci_log_hdl,
663 	    "uhci_rem_intrs: interrupt type 0x%x", uhcip->uhci_intr_type);
664 
665 	/* Disable all interrupts */
666 	if (uhcip->uhci_intr_cap & DDI_INTR_FLAG_BLOCK) {
667 		(void) ddi_intr_block_disable(uhcip->uhci_htable,
668 		    uhcip->uhci_intr_cnt);
669 	} else {
670 		for (i = 0; i < uhcip->uhci_intr_cnt; i++) {
671 			(void) ddi_intr_disable(uhcip->uhci_htable[i]);
672 		}
673 	}
674 
675 	/* Call ddi_intr_remove_handler() */
676 	for (i = 0; i < uhcip->uhci_intr_cnt; i++) {
677 		(void) ddi_intr_remove_handler(uhcip->uhci_htable[i]);
678 		(void) ddi_intr_free(uhcip->uhci_htable[i]);
679 	}
680 
681 	kmem_free(uhcip->uhci_htable,
682 	    uhcip->uhci_intr_cnt * sizeof (ddi_intr_handle_t));
683 }
684 
685 
686 /*
687  * Function Name:	uhci_reset
688  * Description:		Reset entry point - called by the Kernel
689  *			on the way down.
690  *			The Toshiba laptop has been observed to	hang
691  *			on reboot when BIOS is set to suspend/resume.
692  *			The resetting uhci on the way down solves the
693  *			problem.
694  * Output:		DDI_SUCCESS / DDI_FAILURE
695  */
696 /* ARGSUSED */
697 static int
698 uhci_reset(dev_info_t *dip, ddi_reset_cmd_t cmd)
699 {
700 	uhci_state_t	*uhcip = uhci_obtain_state(dip);
701 
702 	/* Disable all HC ED list processing */
703 	Set_OpReg16(USBINTR, DISABLE_ALL_INTRS);
704 	Set_OpReg16(USBCMD, 0);
705 
706 	return (DDI_SUCCESS);
707 }
708 
709 
710 /*
711  * uhci_info:
712  */
713 /* ARGSUSED */
714 static int
715 uhci_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
716 {
717 	dev_t		dev;
718 	int		instance;
719 	int		error = DDI_FAILURE;
720 	uhci_state_t	*uhcip;
721 
722 	switch (infocmd) {
723 	case DDI_INFO_DEVT2DEVINFO:
724 		dev = (dev_t)arg;
725 		instance = UHCI_UNIT(dev);
726 		uhcip = ddi_get_soft_state(uhci_statep, instance);
727 		if (uhcip != NULL) {
728 			*result = (void *)uhcip->uhci_dip;
729 			if (*result != NULL) {
730 				error = DDI_SUCCESS;
731 			}
732 		} else {
733 			*result = NULL;
734 		}
735 
736 		break;
737 	case DDI_INFO_DEVT2INSTANCE:
738 		dev = (dev_t)arg;
739 		instance = UHCI_UNIT(dev);
740 		*result = (void *)(uintptr_t)instance;
741 		error = DDI_SUCCESS;
742 
743 		break;
744 	default:
745 		break;
746 	}
747 
748 	return (error);
749 }
750 
751 
752 /*
753  * uhci_cleanup:
754  *	Cleanup on attach failure or detach
755  */
756 static int
757 uhci_cleanup(uhci_state_t *uhcip)
758 {
759 	USB_DPRINTF_L4(PRINT_MASK_ATTA, uhcip->uhci_log_hdl, "uhci_cleanup:");
760 
761 	if (usba_hubdi_unbind_root_hub(uhcip->uhci_dip) != USB_SUCCESS) {
762 
763 		return (USB_FAILURE);
764 	}
765 
766 	mutex_enter(&uhcip->uhci_int_mutex);
767 
768 	if (uhcip->uhci_cmd_timeout_id) {
769 		timeout_id_t timeout_id = uhcip->uhci_cmd_timeout_id;
770 		uhcip->uhci_cmd_timeout_id = 0;
771 		mutex_exit(&uhcip->uhci_int_mutex);
772 		(void) untimeout(timeout_id);
773 		mutex_enter(&uhcip->uhci_int_mutex);
774 	}
775 
776 	uhci_uninit_ctlr(uhcip);
777 
778 	mutex_exit(&uhcip->uhci_int_mutex);
779 
780 	/* do interrupt cleanup */
781 	if (uhcip->uhci_htable) {
782 		uhci_rem_intrs(uhcip);
783 	}
784 
785 	mutex_enter(&uhcip->uhci_int_mutex);
786 
787 	usba_hcdi_unregister(uhcip->uhci_dip);
788 
789 	uhci_unmap_regs(uhcip);
790 
791 	uhci_free_pools(uhcip);
792 
793 	mutex_exit(&uhcip->uhci_int_mutex);
794 
795 	mutex_destroy(&uhcip->uhci_int_mutex);
796 	cv_destroy(&uhcip->uhci_cv_SOF);
797 	sema_destroy(&uhcip->uhci_ocsem);
798 
799 	/* cleanup kstat structures */
800 	uhci_destroy_stats(uhcip);
801 
802 	usba_free_hcdi_ops(uhcip->uhci_hcdi_ops);
803 	usb_free_log_hdl(uhcip->uhci_log_hdl);
804 	ddi_prop_remove_all(uhcip->uhci_dip);
805 	ddi_soft_state_free(uhci_statep, uhcip->uhci_instance);
806 
807 	return (USB_SUCCESS);
808 }
809 
810 
811 /*
812  * uhci_intr:
813  *	uhci interrupt handling routine.
814  */
815 static uint_t
816 uhci_intr(caddr_t arg1, caddr_t arg2)
817 {
818 	ushort_t	intr_status, cmd_reg;
819 	uhci_state_t	*uhcip = (uhci_state_t *)arg1;
820 
821 	USB_DPRINTF_L3(PRINT_MASK_INTR, uhcip->uhci_log_hdl,
822 	    "uhci_intr: Interrupt occurred, arg1 0x%p arg2 0x%p", arg1, arg2);
823 
824 	mutex_enter(&uhcip->uhci_int_mutex);
825 
826 	/* Get the status of the interrupts */
827 	intr_status = Get_OpReg16(USBSTS);
828 
829 	USB_DPRINTF_L4(PRINT_MASK_INTR, uhcip->uhci_log_hdl,
830 	    "uhci_intr: intr_status = %x", intr_status);
831 
832 	/*
833 	 * If the intr is not from our controller, just return unclaimed
834 	 */
835 	if (!(intr_status & UHCI_INTR_MASK)) {
836 
837 		USB_DPRINTF_L3(PRINT_MASK_INTR, uhcip->uhci_log_hdl,
838 		    "uhci_intr: unclaimed interrupt");
839 		mutex_exit(&uhcip->uhci_int_mutex);
840 
841 		return (DDI_INTR_UNCLAIMED);
842 	}
843 
844 	/* Update kstat values */
845 	uhci_do_intrs_stats(uhcip, intr_status);
846 
847 	/* Acknowledge the interrupt */
848 	Set_OpReg16(USBSTS, intr_status);
849 
850 	/*
851 	 * If uhci controller has not been initialized, just clear the
852 	 * interrupter status and return claimed.
853 	 */
854 	if (uhcip->uhci_ctlr_init_flag != B_TRUE) {
855 
856 		USB_DPRINTF_L2(PRINT_MASK_INTR, uhcip->uhci_log_hdl,
857 		    "uhci_intr: uhci controller has not been fully"
858 		    "initialized");
859 		mutex_exit(&uhcip->uhci_int_mutex);
860 
861 		return (DDI_INTR_CLAIMED);
862 	}
863 
864 	/*
865 	 * We configured the hw incorrectly, disable future interrupts.
866 	 */
867 	if ((intr_status & USBSTS_REG_HOST_SYS_ERR)) {
868 		USB_DPRINTF_L2(PRINT_MASK_INTR, uhcip->uhci_log_hdl,
869 		    "uhci_intr: Sys Err Disabling Interrupt");
870 		Set_OpReg16(USBINTR, DISABLE_ALL_INTRS);
871 		mutex_exit(&uhcip->uhci_int_mutex);
872 
873 		return (DDI_INTR_CLAIMED);
874 	}
875 
876 	/*
877 	 * Check whether a frame number overflow occurred.
878 	 * if so, update the sw frame number.
879 	 */
880 	uhci_isoc_update_sw_frame_number(uhcip);
881 
882 	/*
883 	 * Check whether any commands got completed. If so, process them.
884 	 */
885 	uhci_process_submitted_td_queue(uhcip);
886 
887 	/*
888 	 * This should not occur. It occurs only if a HC controller
889 	 * experiences internal problem.
890 	 */
891 	if (intr_status & USBSTS_REG_HC_HALTED) {
892 		USB_DPRINTF_L2(PRINT_MASK_INTR, uhcip->uhci_log_hdl,
893 		    "uhci_intr: Controller halted");
894 		cmd_reg = Get_OpReg16(USBCMD);
895 		Set_OpReg16(USBCMD, (cmd_reg | USBCMD_REG_HC_RUN));
896 	}
897 
898 	/*
899 	 * Wake up all the threads which are waiting for the Start of Frame
900 	 */
901 	if (uhcip->uhci_cv_signal == B_TRUE) {
902 		cv_broadcast(&uhcip->uhci_cv_SOF);
903 		uhcip->uhci_cv_signal = B_FALSE;
904 	}
905 
906 	mutex_exit(&uhcip->uhci_int_mutex);
907 
908 	return (DDI_INTR_CLAIMED);
909 }
910 
911 
912 /*
913  * uhci_process_submitted_td_queue:
914  *    Traverse thru the submitted queue and process the completed ones.
915  */
916 void
917 uhci_process_submitted_td_queue(uhci_state_t *uhcip)
918 {
919 	uhci_td_t		*head = uhcip->uhci_outst_tds_head;
920 	uhci_trans_wrapper_t	*tw;
921 
922 	while (head != NULL) {
923 		if ((!(GetTD_status(uhcip, head) & UHCI_TD_ACTIVE)) &&
924 		    (head->tw->tw_claim == UHCI_NOT_CLAIMED)) {
925 			tw = head->tw;
926 
927 			/*
928 			 * Call the corresponding handle_td routine
929 			 */
930 			(*tw->tw_handle_td)(uhcip, head);
931 
932 			/* restart at the beginning again */
933 			head = uhcip->uhci_outst_tds_head;
934 		} else {
935 			head = head->outst_td_next;
936 		}
937 	}
938 }
939 
940 
941 /*
942  * uhci_handle_intr_td:
943  *     handles the completed interrupt transfer TD's.
944  */
945 void
946 uhci_handle_intr_td(uhci_state_t *uhcip, uhci_td_t *td)
947 {
948 	usb_req_attrs_t		attrs;
949 	uint_t			bytes_xfered;
950 	usb_cr_t		usb_err;
951 	uhci_trans_wrapper_t	*tw = td->tw;
952 	uhci_pipe_private_t	*pp = tw->tw_pipe_private;
953 	usb_intr_req_t		*intr_reqp =
954 				    (usb_intr_req_t *)tw->tw_curr_xfer_reqp;
955 	usba_pipe_handle_data_t	*ph = pp->pp_pipe_handle;
956 
957 	USB_DPRINTF_L4(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
958 	    "uhci_handle_intr_td: intr_reqp = 0x%p", (void *)intr_reqp);
959 
960 	ASSERT(mutex_owned(&uhcip->uhci_int_mutex));
961 
962 	/* set tw->tw_claim flag, so that nobody else works on this td. */
963 	tw->tw_claim = UHCI_INTR_HDLR_CLAIMED;
964 
965 	/* Interrupt OUT */
966 	if (UHCI_XFER_DIR(&ph->p_ep) == USB_EP_DIR_OUT) {
967 
968 		/* process errors first */
969 		usb_err = uhci_parse_td_error(uhcip, pp, td);
970 
971 		/* get the actual xfered data size */
972 		bytes_xfered = GetTD_alen(uhcip, td);
973 
974 		/* check data underrun error */
975 		if ((usb_err == USB_CR_OK) && (bytes_xfered !=
976 		    GetTD_mlen(uhcip, td))) {
977 
978 			USB_DPRINTF_L2(PRINT_MASK_LISTS,
979 			    uhcip->uhci_log_hdl, "uhci_handle_intr_td:"
980 			    " Intr out pipe, data underrun occurred");
981 
982 			usb_err = USB_CR_DATA_UNDERRUN;
983 
984 		}
985 
986 		bytes_xfered = (bytes_xfered == ZERO_LENGTH) ?
987 						0 : bytes_xfered+1;
988 		tw->tw_bytes_xfered += bytes_xfered;
989 		uhci_do_byte_stats(uhcip, tw->tw_bytes_xfered,
990 		    ph->p_ep.bmAttributes, ph->p_ep.bEndpointAddress);
991 
992 
993 		/*
994 		 * If error occurred or all data xfered, delete the current td,
995 		 * free tw, do the callback. Otherwise wait for the next td.
996 		 */
997 		if (usb_err != USB_CR_OK) {
998 
999 			USB_DPRINTF_L2(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
1000 			    "uhci_handle_intr_td: Intr out pipe error");
1001 
1002 			/* update the element pointer */
1003 			SetQH32(uhcip, pp->pp_qh->element_ptr, GetTD32(
1004 				uhcip, tw->tw_hctd_tail->link_ptr));
1005 
1006 
1007 		} else if (tw->tw_bytes_xfered == tw->tw_length) {
1008 
1009 			/* all data xfered */
1010 			USB_DPRINTF_L3(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
1011 			    "uhci_handle_intr_td: Intr out pipe,"
1012 			    " all data xfered");
1013 
1014 		} else {
1015 
1016 			/* remove the current td and wait for the next one. */
1017 			uhci_delete_td(uhcip, td);
1018 			tw->tw_claim = UHCI_NOT_CLAIMED;
1019 
1020 			return;
1021 		}
1022 
1023 		uhci_delete_td(uhcip, td);
1024 		uhci_hcdi_callback(uhcip, pp, ph, tw, usb_err);
1025 		uhci_deallocate_tw(uhcip, tw->tw_pipe_private, tw);
1026 
1027 		return;
1028 	}
1029 
1030 	/* Interrupt IN */
1031 
1032 	/* Get the actual received data size */
1033 	tw->tw_bytes_xfered = GetTD_alen(uhcip, td);
1034 	if (tw->tw_bytes_xfered == ZERO_LENGTH) {
1035 		tw->tw_bytes_xfered = 0;
1036 	} else {
1037 		tw->tw_bytes_xfered++;
1038 	}
1039 
1040 	/* process errors first */
1041 	if (GetTD_status(uhcip, td) & TD_STATUS_MASK) {
1042 		SetQH32(uhcip, pp->pp_qh->element_ptr,
1043 		    GetTD32(uhcip, td->link_ptr));
1044 
1045 		uhci_handle_intr_td_errors(uhcip, td, tw, pp);
1046 
1047 		return;
1048 	}
1049 
1050 	/*
1051 	 * Check for data underruns.
1052 	 * For data underrun case, the host controller does not update
1053 	 * element pointer. So, we update here.
1054 	 */
1055 	if (GetTD_alen(uhcip, td) != GetTD_mlen(uhcip, td)) {
1056 		SetQH32(uhcip, pp->pp_qh->element_ptr,
1057 		    GetTD32(uhcip, td->link_ptr));
1058 	}
1059 
1060 	/*
1061 	 * Call uhci_sendup_td_message to send message upstream.
1062 	 * The function uhci_sendup_td_message returns USB_NO_RESOURCES
1063 	 * if allocb fails and also sends error message to upstream by
1064 	 * calling USBA callback function. Under error conditions just
1065 	 * drop the current message.
1066 	 */
1067 
1068 	/* Get the interrupt xfer attributes */
1069 	attrs = intr_reqp->intr_attributes;
1070 
1071 	/*
1072 	 * Check usb flag whether USB_FLAGS_ONE_XFER flag is set
1073 	 * and if so, free duplicate request.
1074 	 */
1075 	if (attrs & USB_ATTRS_ONE_XFER) {
1076 		uhci_handle_one_xfer_completion(uhcip, USB_CR_OK, td);
1077 
1078 		return;
1079 	}
1080 
1081 	/* save it temporarily */
1082 	if (tw->tw_bytes_xfered != 0) {
1083 		uhci_sendup_td_message(uhcip, USB_CR_OK, tw);
1084 	}
1085 
1086 	/* Clear the tw->tw_claim flag */
1087 	tw->tw_claim = UHCI_NOT_CLAIMED;
1088 
1089 	uhci_delete_td(uhcip, td);
1090 
1091 	/* allocate another interrupt periodic resource */
1092 	if (pp->pp_state == UHCI_PIPE_STATE_ACTIVE) {
1093 		if (uhci_allocate_periodic_in_resource(uhcip, pp, tw, 0) !=
1094 		    USB_SUCCESS) {
1095 			USB_DPRINTF_L2(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
1096 			    "uhci_insert_intr_req: Interrupt request structure"
1097 			    "allocation failed");
1098 
1099 			uhci_hcdi_callback(uhcip, pp, ph,
1100 			    tw, USB_CR_NO_RESOURCES);
1101 
1102 			return;
1103 		}
1104 
1105 		/* Insert another interrupt TD */
1106 		if (uhci_insert_hc_td(uhcip, 0,
1107 		    tw->tw_length, pp, tw, PID_IN, attrs) != USB_SUCCESS) {
1108 
1109 			uhci_deallocate_periodic_in_resource(uhcip, pp, tw);
1110 
1111 			USB_DPRINTF_L2(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
1112 			    "uhci_handle_intr_td: TD exhausted");
1113 
1114 			uhci_hcdi_callback(uhcip, pp, ph,
1115 			    tw, USB_CR_NO_RESOURCES);
1116 		}
1117 	}
1118 }
1119 
1120 
1121 /*
1122  * uhci_sendup_td_message:
1123  *
1124  * Get a message block and send the received message upstream.
1125  */
1126 void
1127 uhci_sendup_td_message(
1128 	uhci_state_t		*uhcip,
1129 	usb_cr_t		usb_err,
1130 	uhci_trans_wrapper_t	*tw)
1131 {
1132 	mblk_t			*mp = NULL;
1133 	size_t			length = 0;
1134 	size_t			skip_len = 0;
1135 	uchar_t			*buf;
1136 	usb_opaque_t		curr_xfer_reqp = tw->tw_curr_xfer_reqp;
1137 	uhci_pipe_private_t	*pp = tw->tw_pipe_private;
1138 	usb_ep_descr_t		*ept = &pp->pp_pipe_handle->p_ep;
1139 
1140 	ASSERT(mutex_owned(&uhcip->uhci_int_mutex));
1141 
1142 	USB_DPRINTF_L4(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
1143 	    "uhci_sendup_td_message: bytes transferred=0x%x, "
1144 	    "bytes pending=0x%x",
1145 	    tw->tw_bytes_xfered, tw->tw_bytes_pending);
1146 
1147 	length = tw->tw_bytes_xfered;
1148 
1149 	switch (UHCI_XFER_TYPE(ept)) {
1150 	case USB_EP_ATTR_CONTROL:
1151 		skip_len = UHCI_CTRL_EPT_MAX_SIZE; /* length to skip */
1152 		mp = ((usb_ctrl_req_t *)curr_xfer_reqp)->ctrl_data;
1153 		break;
1154 	case USB_EP_ATTR_INTR:
1155 		mp = ((usb_intr_req_t *)curr_xfer_reqp)->intr_data;
1156 		break;
1157 	case USB_EP_ATTR_BULK:
1158 		mp = ((usb_bulk_req_t *)curr_xfer_reqp)->bulk_data;
1159 		break;
1160 	case USB_EP_ATTR_ISOCH:
1161 		length = tw->tw_length;
1162 		mp = ((usb_isoc_req_t *)curr_xfer_reqp)->isoc_data;
1163 		break;
1164 	default:
1165 		break;
1166 	}
1167 
1168 	/* Copy the data into the mblk_t */
1169 	buf = (uchar_t *)tw->tw_buf + skip_len;
1170 
1171 	ASSERT(mp != NULL);
1172 
1173 	/*
1174 	 * Update kstat byte counts
1175 	 * The control endpoints don't have direction bits so in
1176 	 * order for control stats to be counted correctly an IN
1177 	 * bit must be faked on a control read.
1178 	 */
1179 	uhci_do_byte_stats(uhcip, length, ept->bmAttributes,
1180 	    (UHCI_XFER_TYPE(ept) == USB_EP_ATTR_CONTROL) ?
1181 	    USB_EP_DIR_IN : ept->bEndpointAddress);
1182 
1183 	if (length) {
1184 		int rval, i;
1185 		uchar_t *p = mp->b_rptr;
1186 
1187 		if (UHCI_XFER_TYPE(ept) == USB_EP_ATTR_ISOCH) {
1188 			/* Deal with isoc data by packets */
1189 			for (i = 0; i < tw->tw_ncookies; i++) {
1190 				rval = ddi_dma_sync(
1191 				    tw->tw_isoc_bufs[i].dma_handle, 0,
1192 				    tw->tw_isoc_bufs[i].length,
1193 				    DDI_DMA_SYNC_FORCPU);
1194 				ASSERT(rval == DDI_SUCCESS);
1195 
1196 				ddi_rep_get8(tw->tw_isoc_bufs[i].mem_handle,
1197 				    p, (uint8_t *)tw->tw_isoc_bufs[i].buf_addr,
1198 				    tw->tw_isoc_bufs[i].length,
1199 				    DDI_DEV_AUTOINCR);
1200 				p += tw->tw_isoc_bufs[i].length;
1201 			}
1202 		} else {
1203 			/* Sync the streaming buffer */
1204 			rval = ddi_dma_sync(tw->tw_dmahandle, 0,
1205 			    (skip_len + length), DDI_DMA_SYNC_FORCPU);
1206 			ASSERT(rval == DDI_SUCCESS);
1207 
1208 			/* Copy the data into the message */
1209 			ddi_rep_get8(tw->tw_accesshandle,
1210 			    mp->b_rptr, buf, length, DDI_DEV_AUTOINCR);
1211 		}
1212 
1213 		/* Increment the write pointer */
1214 		mp->b_wptr += length;
1215 	} else {
1216 		USB_DPRINTF_L3(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
1217 		    "uhci_sendup_td_message: Zero length packet");
1218 	}
1219 
1220 	/* Do the callback */
1221 	uhci_hcdi_callback(uhcip, pp, pp->pp_pipe_handle, tw, usb_err);
1222 }
1223 
1224 
1225 /*
1226  * uhci_handle_ctrl_td:
1227  *	Handle a control Transfer Descriptor (TD).
1228  */
1229 void
1230 uhci_handle_ctrl_td(uhci_state_t *uhcip, uhci_td_t *td)
1231 {
1232 	ushort_t		direction;
1233 	ushort_t		bytes_for_xfer;
1234 	ushort_t		bytes_xfered;
1235 	ushort_t		MaxPacketSize;
1236 	usb_cr_t		error;
1237 	uhci_trans_wrapper_t	*tw = td->tw;
1238 	uhci_pipe_private_t	*pp = tw->tw_pipe_private;
1239 	usba_pipe_handle_data_t	*usb_pp = pp->pp_pipe_handle;
1240 	usb_ep_descr_t		*eptd = &usb_pp->p_ep;
1241 	usb_ctrl_req_t		*reqp = (usb_ctrl_req_t *)tw->tw_curr_xfer_reqp;
1242 
1243 	USB_DPRINTF_L4(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
1244 	    "uhci_handle_ctrl_td: pp = 0x%p tw = 0x%p td = 0x%p "
1245 	    "state = 0x%x len = 0x%lx", (void *)pp, (void *)tw,
1246 	    (void *)td, tw->tw_ctrl_state, tw->tw_length);
1247 
1248 	ASSERT(mutex_owned(&uhcip->uhci_int_mutex));
1249 
1250 	error = uhci_parse_td_error(uhcip, pp, td);
1251 
1252 	/*
1253 	 * In case of control transfers, the device can send NAK when it
1254 	 * is busy. If a NAK is received, then send the status TD again.
1255 	 */
1256 	if (error != USB_CR_OK) {
1257 		USB_DPRINTF_L3(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
1258 		    "uhci_handle_ctrl_td: Ctrl cmd failed, error = %x", error);
1259 
1260 		SetQH32(uhcip, pp->pp_qh->element_ptr,
1261 		    GetTD32(uhcip, td->link_ptr));
1262 		uhci_delete_td(uhcip, td);
1263 
1264 		/* Return number of bytes xfered */
1265 		if (GetTD_alen(uhcip, td) != ZERO_LENGTH) {
1266 			tw->tw_bytes_xfered = GetTD_alen(uhcip, td) + 1;
1267 		}
1268 
1269 		USB_DPRINTF_L3(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
1270 		    "uhci_handle_ctrl_td: Bytes transferred = %x",
1271 		    tw->tw_bytes_xfered);
1272 
1273 		if ((tw->tw_ctrl_state == DATA) &&
1274 		    (tw->tw_direction == PID_IN)) {
1275 			uhci_sendup_td_message(uhcip, error, tw);
1276 		} else {
1277 			uhci_hcdi_callback(uhcip, pp, usb_pp, tw, error);
1278 
1279 			uhci_deallocate_tw(uhcip, pp, tw);
1280 		}
1281 
1282 		return;
1283 	}
1284 
1285 	/*
1286 	 * A control transfer consists of three phases:
1287 	 *	- Setup
1288 	 *	- Data (optional)
1289 	 *	- Status
1290 	 *
1291 	 * There is a TD per phase. A TD for a given phase isn't
1292 	 * enqueued until the previous phase is finished.
1293 	 */
1294 	switch (tw->tw_ctrl_state) {
1295 	case SETUP:
1296 		/*
1297 		 * Enqueue either the data or the status
1298 		 * phase depending on the length.
1299 		 */
1300 		pp->pp_data_toggle = 1;
1301 		uhci_delete_td(uhcip, td);
1302 
1303 		/*
1304 		 * If the length is 0, move to the status.
1305 		 * If length is not 0, then we have some data
1306 		 * to move on the bus to device either IN or OUT.
1307 		 */
1308 		if ((tw->tw_length - SETUP_SIZE) == 0) {
1309 			/*
1310 			 * There is no data stage,  then
1311 			 * initiate status phase from the host.
1312 			 */
1313 			if ((uhci_insert_hc_td(uhcip, 0, 0, pp, tw, PID_IN,
1314 			    reqp->ctrl_attributes)) != USB_SUCCESS) {
1315 				USB_DPRINTF_L2(PRINT_MASK_LISTS,
1316 				    uhcip->uhci_log_hdl,
1317 				    "uhci_handle_ctrl_td: No resources");
1318 
1319 				uhci_hcdi_callback(uhcip, pp, usb_pp, tw,
1320 				    USB_CR_NO_RESOURCES);
1321 
1322 				return;
1323 			}
1324 
1325 			tw->tw_ctrl_state = STATUS;
1326 		} else {
1327 			uint_t xx;
1328 
1329 			/*
1330 			 * Each USB device can send/receive 8/16/32/64
1331 			 * depending on wMaxPacketSize's implementation.
1332 			 * We need to insert 'N = Number of byte/
1333 			 * MaxpktSize" TD's in the lattice to send/
1334 			 * receive the data. Though the USB protocol
1335 			 * allows to insert more than one TD in the same
1336 			 * frame, we are inserting only one TD in one
1337 			 * frame. This is bcos OHCI has seen some problem
1338 			 * when multiple TD's are inserted at the same time.
1339 			 */
1340 			tw->tw_length -= UHCI_CTRL_EPT_MAX_SIZE;
1341 			MaxPacketSize = eptd->wMaxPacketSize;
1342 
1343 			/*
1344 			 * We dont know the maximum packet size that
1345 			 * the device can handle(MaxPAcketSize=0).
1346 			 * In that case insert a data phase with
1347 			 * eight bytes or less.
1348 			 */
1349 			if (MaxPacketSize == 0) {
1350 				xx = (tw->tw_length > 8) ? 8 : tw->tw_length;
1351 			} else {
1352 				xx = (tw->tw_length > MaxPacketSize) ?
1353 					MaxPacketSize : tw->tw_length;
1354 			}
1355 
1356 			tw->tw_tmp = xx;
1357 
1358 			/*
1359 			 * Create the TD.  If this is an OUT
1360 			 * transaction,  the data is already
1361 			 * in the buffer of the TW.
1362 			 * Get first 8 bytes of the command only.
1363 			 */
1364 			if ((uhci_insert_hc_td(uhcip,
1365 			    UHCI_CTRL_EPT_MAX_SIZE, xx,
1366 			    pp, tw, tw->tw_direction,
1367 			    reqp->ctrl_attributes)) != USB_SUCCESS) {
1368 
1369 				USB_DPRINTF_L2(PRINT_MASK_LISTS,
1370 				    uhcip->uhci_log_hdl,
1371 				    "uhci_handle_ctrl_td: No resources");
1372 
1373 				uhci_hcdi_callback(uhcip, pp, usb_pp, tw,
1374 				    USB_CR_NO_RESOURCES);
1375 
1376 				return;
1377 			}
1378 
1379 			tw->tw_ctrl_state = DATA;
1380 		}
1381 
1382 		USB_DPRINTF_L3(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
1383 		    "Setup complete: pp 0x%p td 0x%p", (void *)pp, (void *)td);
1384 
1385 		break;
1386 	case DATA:
1387 		uhci_delete_td(uhcip, td);
1388 
1389 		MaxPacketSize = eptd->wMaxPacketSize;
1390 
1391 		/*
1392 		 * Decrement pending bytes and increment the total
1393 		 * number bytes transferred by the actual number of bytes
1394 		 * transferred in this TD. If the number of bytes transferred
1395 		 * is less than requested, that means an underrun has
1396 		 * occurred. Set the tw_tmp varible to indicate UNDER run.
1397 		 */
1398 		bytes_xfered = GetTD_alen(uhcip, td);
1399 		if (bytes_xfered == ZERO_LENGTH) {
1400 			bytes_xfered = 0;
1401 		} else {
1402 			bytes_xfered++;
1403 		}
1404 
1405 		tw->tw_bytes_pending -= bytes_xfered;
1406 		tw->tw_bytes_xfered += bytes_xfered;
1407 
1408 		if (bytes_xfered < tw->tw_tmp) {
1409 			tw->tw_bytes_pending = 0;
1410 			tw->tw_tmp = UHCI_UNDERRUN_OCCURRED;
1411 
1412 			/*
1413 			 * Controller does not update the queue head
1414 			 * element pointer when a data underrun occurs.
1415 			 */
1416 			SetQH32(uhcip, pp->pp_qh->element_ptr,
1417 			    GetTD32(uhcip, td->link_ptr));
1418 		}
1419 
1420 		if (bytes_xfered > tw->tw_tmp) {
1421 			tw->tw_bytes_pending = 0;
1422 			tw->tw_tmp = UHCI_OVERRUN_OCCURRED;
1423 		}
1424 
1425 		/*
1426 		 * If no more bytes are pending, insert status
1427 		 * phase. Otherwise insert data phase.
1428 		 */
1429 		if (tw->tw_bytes_pending) {
1430 			bytes_for_xfer = (tw->tw_bytes_pending >
1431 					MaxPacketSize) ? MaxPacketSize :
1432 					tw->tw_bytes_pending;
1433 
1434 			tw->tw_tmp = bytes_for_xfer;
1435 
1436 			if ((uhci_insert_hc_td(uhcip,
1437 			    UHCI_CTRL_EPT_MAX_SIZE + tw->tw_bytes_xfered,
1438 			    bytes_for_xfer, pp, tw,
1439 			    tw->tw_direction,
1440 			    reqp->ctrl_attributes)) != USB_SUCCESS) {
1441 				USB_DPRINTF_L2(PRINT_MASK_LISTS,
1442 				    uhcip->uhci_log_hdl,
1443 				    "uhci_handle_ctrl_td: No TD");
1444 
1445 				uhci_hcdi_callback(uhcip, pp, usb_pp,
1446 				    tw, USB_NO_RESOURCES);
1447 
1448 				return;
1449 			}
1450 
1451 			tw->tw_ctrl_state = DATA;
1452 
1453 			break;
1454 		}
1455 
1456 		pp->pp_data_toggle = 1;
1457 		direction = (tw->tw_direction == PID_IN) ? PID_OUT : PID_IN;
1458 
1459 		if ((uhci_insert_hc_td(uhcip, 0, 0, pp, tw, direction,
1460 		    reqp->ctrl_attributes)) != USB_SUCCESS) {
1461 			USB_DPRINTF_L2(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
1462 			    "uhci_handle_ctrl_td: TD exhausted");
1463 
1464 			uhci_hcdi_callback(uhcip, pp, usb_pp, tw,
1465 			    USB_NO_RESOURCES);
1466 
1467 			return;
1468 		}
1469 
1470 		tw->tw_ctrl_state = STATUS;
1471 		USB_DPRINTF_L3(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
1472 		    "Data complete: pp 0x%p td 0x%p", (void *)pp, (void *)td);
1473 
1474 		break;
1475 	case STATUS:
1476 		/*
1477 		 * Send the data to the client if it is a DATA IN,
1478 		 * else send just return status for DATA OUT commnads.
1479 		 * And set the tw_claim flag.
1480 		 */
1481 		tw->tw_claim = UHCI_INTR_HDLR_CLAIMED;
1482 
1483 		if ((tw->tw_length != 0) && (tw->tw_direction == PID_IN)) {
1484 			usb_req_attrs_t	attrs = ((usb_ctrl_req_t *)
1485 					tw->tw_curr_xfer_reqp)->ctrl_attributes;
1486 			/*
1487 			 * Call uhci_sendup_td_message to send message
1488 			 * upstream. The function uhci_sendup_td_message
1489 			 * returns USB_NO_RESOURCES if allocb fails and
1490 			 * also sends error message to upstream by calling
1491 			 * USBA callback function.
1492 			 *
1493 			 * Under error conditions just drop the current msg.
1494 			 */
1495 			if ((tw->tw_tmp == UHCI_UNDERRUN_OCCURRED) &&
1496 			    (!(attrs & USB_ATTRS_SHORT_XFER_OK))) {
1497 				error = USB_CR_DATA_UNDERRUN;
1498 			} else if (tw->tw_tmp == UHCI_OVERRUN_OCCURRED) {
1499 				error = USB_CR_DATA_OVERRUN;
1500 			}
1501 			uhci_sendup_td_message(uhcip, error, tw);
1502 
1503 		} else {
1504 			uhci_do_byte_stats(uhcip, tw->tw_length,
1505 			    eptd->bmAttributes, eptd->bEndpointAddress);
1506 
1507 			uhci_hcdi_callback(uhcip, pp, usb_pp, tw, USB_CR_OK);
1508 		}
1509 
1510 		USB_DPRINTF_L3(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
1511 		    "Status complete: pp 0x%p td 0x%p", pp, td);
1512 
1513 		uhci_delete_td(uhcip, td);
1514 		uhci_deallocate_tw(uhcip, pp, tw);
1515 
1516 		break;
1517 	default:
1518 		USB_DPRINTF_L2(PRINT_MASK_INTR, uhcip->uhci_log_hdl,
1519 		    "uhci_handle_ctrl_td: Bad control state");
1520 
1521 		uhci_hcdi_callback(uhcip, pp, usb_pp, tw,
1522 		    USB_CR_UNSPECIFIED_ERR);
1523 	}
1524 }
1525 
1526 
1527 /*
1528  * uhci_handle_intr_td_errors:
1529  *	Handles the errors encountered for the interrupt transfers.
1530  */
1531 static void
1532 uhci_handle_intr_td_errors(uhci_state_t *uhcip, uhci_td_t *td,
1533     uhci_trans_wrapper_t *tw, uhci_pipe_private_t *pp)
1534 {
1535 	usb_cr_t		usb_err;
1536 	usb_intr_req_t		*intr_reqp =
1537 				    (usb_intr_req_t *)tw->tw_curr_xfer_reqp;
1538 
1539 	USB_DPRINTF_L4(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
1540 	    "uhci_handle_intr_td_errors: td = 0x%p tw = 0x%p", td, tw);
1541 
1542 	usb_err = uhci_parse_td_error(uhcip, pp, td);
1543 
1544 	if (intr_reqp->intr_attributes & USB_ATTRS_ONE_XFER) {
1545 		uhci_handle_one_xfer_completion(uhcip, usb_err, td);
1546 
1547 		return;
1548 	}
1549 
1550 	uhci_delete_td(uhcip, td);
1551 	uhci_sendup_td_message(uhcip, usb_err, tw);
1552 	uhci_deallocate_tw(uhcip, tw->tw_pipe_private, tw);
1553 }
1554 
1555 
1556 /*
1557  * uhci_handle_one_xfer_completion:
1558  */
1559 static void
1560 uhci_handle_one_xfer_completion(
1561 	uhci_state_t		*uhcip,
1562 	usb_cr_t		usb_err,
1563 	uhci_td_t		*td)
1564 {
1565 	uhci_trans_wrapper_t	*tw = td->tw;
1566 	uhci_pipe_private_t	*pp = tw->tw_pipe_private;
1567 	usba_pipe_handle_data_t	*ph = pp->pp_pipe_handle;
1568 	usb_intr_req_t		*intr_reqp =
1569 				    (usb_intr_req_t *)tw->tw_curr_xfer_reqp;
1570 
1571 	USB_DPRINTF_L4(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
1572 	    "uhci_handle_one_xfer_completion: td = 0x%p", td);
1573 
1574 	ASSERT(intr_reqp->intr_attributes & USB_ATTRS_ONE_XFER);
1575 
1576 	/* set state to idle */
1577 	pp->pp_state = UHCI_PIPE_STATE_IDLE;
1578 
1579 	((usb_intr_req_t *)(pp->pp_client_periodic_in_reqp))->
1580 	    intr_data = ((usb_intr_req_t *)(tw->tw_curr_xfer_reqp))->intr_data;
1581 
1582 	((usb_intr_req_t *)tw->tw_curr_xfer_reqp)->intr_data = NULL;
1583 
1584 	/* now free duplicate current request */
1585 	usb_free_intr_req((usb_intr_req_t *)tw->tw_curr_xfer_reqp);
1586 	mutex_enter(&ph->p_mutex);
1587 	ph->p_req_count--;
1588 	mutex_exit(&ph->p_mutex);
1589 
1590 	/* make client's request the current request */
1591 	tw->tw_curr_xfer_reqp = pp->pp_client_periodic_in_reqp;
1592 	pp->pp_client_periodic_in_reqp = NULL;
1593 
1594 	uhci_sendup_td_message(uhcip, usb_err, tw);
1595 	/* Clear the tw->tw_claim flag */
1596 	tw->tw_claim = UHCI_NOT_CLAIMED;
1597 
1598 	uhci_delete_td(uhcip, td);
1599 	uhci_deallocate_tw(uhcip, pp, tw);
1600 }
1601 
1602 
1603 /*
1604  * uhci_parse_td_error
1605  *	Parses the Transfer Descriptors error
1606  */
1607 usb_cr_t
1608 uhci_parse_td_error(uhci_state_t *uhcip, uhci_pipe_private_t *pp, uhci_td_t *td)
1609 {
1610 	uint_t	status;
1611 
1612 	status = GetTD_status(uhcip, td) & TD_STATUS_MASK;
1613 
1614 	USB_DPRINTF_L4(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
1615 	    "uhci_parse_td_error: status_bits=0x%x", status);
1616 
1617 	if (UHCI_XFER_TYPE(&pp->pp_pipe_handle->p_ep) == USB_EP_ATTR_ISOCH) {
1618 
1619 		return (USB_CR_OK);
1620 	}
1621 
1622 	if (!status) {
1623 
1624 		return (USB_CR_OK);
1625 	}
1626 
1627 	USB_DPRINTF_L2(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
1628 	    "uhci_parse_td_error: status_bits=0x%x", status);
1629 
1630 
1631 	if (status & UHCI_TD_BITSTUFF_ERR) {
1632 
1633 		return (USB_CR_BITSTUFFING);
1634 	}
1635 
1636 	if (status & UHCI_TD_CRC_TIMEOUT) {
1637 		pp->pp_data_toggle = GetTD_dtogg(uhcip, td);
1638 
1639 		USB_DPRINTF_L2(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
1640 		    "uhci_parse_td_error: timeout & data toggle reset; "
1641 		    "data toggle: %x", pp->pp_data_toggle);
1642 
1643 		return ((GetTD_PID(uhcip, td) == PID_IN) ? USB_CR_DEV_NOT_RESP :
1644 		    USB_CR_TIMEOUT);
1645 	}
1646 
1647 	if (status & UHCI_TD_BABBLE_ERR) {
1648 		USB_DPRINTF_L2(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
1649 		    "babble error");
1650 
1651 		return (USB_CR_UNSPECIFIED_ERR);
1652 	}
1653 
1654 	if (status & UHCI_TD_DATA_BUFFER_ERR) {
1655 		USB_DPRINTF_L2(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
1656 		    "buffer error");
1657 
1658 		return ((GetTD_PID(uhcip, td) == PID_IN) ?
1659 		    USB_CR_BUFFER_OVERRUN : USB_CR_BUFFER_UNDERRUN);
1660 	}
1661 
1662 	if (status & UHCI_TD_STALLED) {
1663 		pp->pp_data_toggle = 0;
1664 		USB_DPRINTF_L2(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
1665 		    "uhci_parse_td_error: stall; data toggle reset; "
1666 		    "data toggle: %x", pp->pp_data_toggle);
1667 
1668 		return (USB_CR_STALL);
1669 	}
1670 
1671 	if (status) {
1672 		USB_DPRINTF_L2(PRINT_MASK_LISTS, uhcip->uhci_log_hdl,
1673 		    "unspecified error=0x%x", status);
1674 	}
1675 
1676 	return (USB_CR_OK);
1677 }
1678 
1679 
1680 static dev_info_t *
1681 uhci_get_dip(dev_t dev)
1682 {
1683 	int instance = UHCI_UNIT(dev);
1684 	uhci_state_t *uhcip = ddi_get_soft_state(uhci_statep, instance);
1685 
1686 	return (uhcip ? uhcip->uhci_dip : NULL);
1687 }
1688 
1689 
1690 /*
1691  * cb_ops entry points
1692  */
1693 static int
1694 uhci_open(dev_t *devp, int flags, int otyp, cred_t *credp)
1695 {
1696 	dev_info_t *dip = uhci_get_dip(*devp);
1697 
1698 	return (usba_hubdi_open(dip, devp, flags, otyp, credp));
1699 }
1700 
1701 
1702 static int
1703 uhci_close(dev_t dev, int flag, int otyp, cred_t *credp)
1704 {
1705 	dev_info_t *dip = uhci_get_dip(dev);
1706 
1707 	return (usba_hubdi_close(dip, dev, flag, otyp, credp));
1708 }
1709 
1710 
1711 static int
1712 uhci_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
1713     cred_t *credp, int *rvalp)
1714 {
1715 	dev_info_t *dip = uhci_get_dip(dev);
1716 
1717 	return (usba_hubdi_ioctl(dip, dev, cmd, arg, mode, credp, rvalp));
1718 }
1719