diff options
| author | cvs2svn <cvs2svn@FreeBSD.org> | 1999-01-21 00:55:32 +0000 | 
|---|---|---|
| committer | cvs2svn <cvs2svn@FreeBSD.org> | 1999-01-21 00:55:32 +0000 | 
| commit | 76b5366091f76c9bc73570149ef5055648fc2c39 (patch) | |
| tree | 590d020e0f2a5bea6e09d66d951a674443b21d67 /sys/dev/usb/ohci.c | |
| parent | 4b4d01da6f07f7754ff6a6e4f5223e9f0984d1a6 (diff) | |
Diffstat (limited to 'sys/dev/usb/ohci.c')
| -rw-r--r-- | sys/dev/usb/ohci.c | 2228 | 
1 files changed, 0 insertions, 2228 deletions
| diff --git a/sys/dev/usb/ohci.c b/sys/dev/usb/ohci.c deleted file mode 100644 index 1cb64b33769ad..0000000000000 --- a/sys/dev/usb/ohci.c +++ /dev/null @@ -1,2228 +0,0 @@ -/*	$NetBSD: ohci.c,v 1.23 1999/01/07 02:06:05 augustss Exp $	*/ -/*	$FreeBSD$	*/ - -/* - * Copyright (c) 1998 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Lennart Augustsson (augustss@carlstedt.se) at - * Carlstedt Research & Technology. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - *    notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - *    notice, this list of conditions and the following disclaimer in the - *    documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - *    must display the following acknowledgement: - *        This product includes software developed by the NetBSD - *        Foundation, Inc. and its contributors. - * 4. Neither the name of The NetBSD Foundation nor the names of its - *    contributors may be used to endorse or promote products derived - *    from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/* - * USB Open Host Controller driver. - * - * OHCI spec: http://www.intel.com/design/usb/ohci11d.pdf - * USB spec: http://www.teleport.com/cgi-bin/mailmerge.cgi/~usb/cgiform.tpl - */ - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/kernel.h> -#include <sys/malloc.h> -#if defined(__NetBSD__) -#include <sys/device.h> -#elif defined(__FreeBSD__) -#include <sys/module.h> -#include <sys/bus.h> -#endif -#include <sys/proc.h> -#include <sys/queue.h> -#include <sys/select.h> - -#include <machine/bus.h> -#include <machine/endian.h> - -#include <dev/usb/usb.h> -#include <dev/usb/usbdi.h> -#include <dev/usb/usbdivar.h> -#include <dev/usb/usb_quirks.h> -#include <dev/usb/usb_mem.h> - -#include <dev/usb/ohcireg.h> -#include <dev/usb/ohcivar.h> - -#if defined(__FreeBSD__) -#include <machine/clock.h> - -#define delay(d)                DELAY(d) - -#endif - -/* - * The OHCI controller is little endian, so on big endian machines - * the data strored in memory needs to be swapped. - */ -#if BYTE_ORDER == BIG_ENDIAN -#define LE(x) (bswap32(x)) -#else -#define LE(x) (x) -#endif - -struct ohci_pipe; - -ohci_soft_ed_t *ohci_alloc_sed __P((ohci_softc_t *)); -void		ohci_free_sed __P((ohci_softc_t *, ohci_soft_ed_t *)); - -ohci_soft_td_t *ohci_alloc_std __P((ohci_softc_t *)); -void		ohci_free_std __P((ohci_softc_t *, ohci_soft_td_t *)); - -usbd_status	ohci_open __P((usbd_pipe_handle)); -void		ohci_poll __P((struct usbd_bus *)); -void		ohci_waitintr __P((ohci_softc_t *, usbd_request_handle)); -void		ohci_rhsc __P((ohci_softc_t *, usbd_request_handle)); -void		ohci_process_done __P((ohci_softc_t *, ohci_physaddr_t)); -void		ohci_ii_done __P((ohci_softc_t *, usbd_request_handle)); -void		ohci_ctrl_done __P((ohci_softc_t *, usbd_request_handle)); -void		ohci_intr_done __P((ohci_softc_t *, usbd_request_handle)); -void		ohci_bulk_done __P((ohci_softc_t *, usbd_request_handle)); - -usbd_status	ohci_device_request __P((usbd_request_handle reqh)); -void		ohci_add_ed __P((ohci_soft_ed_t *, ohci_soft_ed_t *)); -void		ohci_rem_ed __P((ohci_soft_ed_t *, ohci_soft_ed_t *)); -void		ohci_hash_add_td __P((ohci_softc_t *, ohci_soft_td_t *)); -void		ohci_hash_rem_td __P((ohci_softc_t *, ohci_soft_td_t *)); -ohci_soft_td_t *ohci_hash_find_td __P((ohci_softc_t *, ohci_physaddr_t)); - -usbd_status	ohci_root_ctrl_transfer __P((usbd_request_handle)); -usbd_status	ohci_root_ctrl_start __P((usbd_request_handle)); -void		ohci_root_ctrl_abort __P((usbd_request_handle)); -void		ohci_root_ctrl_close __P((usbd_pipe_handle)); - -usbd_status	ohci_root_intr_transfer __P((usbd_request_handle)); -usbd_status	ohci_root_intr_start __P((usbd_request_handle)); -void		ohci_root_intr_abort __P((usbd_request_handle)); -void		ohci_root_intr_close __P((usbd_pipe_handle)); - -usbd_status	ohci_device_ctrl_transfer __P((usbd_request_handle)); -usbd_status	ohci_device_ctrl_start __P((usbd_request_handle)); -void		ohci_device_ctrl_abort __P((usbd_request_handle)); -void		ohci_device_ctrl_close __P((usbd_pipe_handle)); - -usbd_status	ohci_device_bulk_transfer __P((usbd_request_handle)); -usbd_status	ohci_device_bulk_start __P((usbd_request_handle)); -void		ohci_device_bulk_abort __P((usbd_request_handle)); -void		ohci_device_bulk_close __P((usbd_pipe_handle)); - -usbd_status	ohci_device_intr_transfer __P((usbd_request_handle)); -usbd_status	ohci_device_intr_start __P((usbd_request_handle)); -void		ohci_device_intr_abort __P((usbd_request_handle)); -void		ohci_device_intr_close __P((usbd_pipe_handle)); -usbd_status	ohci_device_setintr __P((ohci_softc_t *sc,  -					 struct ohci_pipe *pipe, int ival)); - -int		ohci_str __P((usb_string_descriptor_t *, int, char *)); - -void		ohci_timeout __P((void *)); -void		ohci_rhsc_able __P((ohci_softc_t *, int)); - -#ifdef USB_DEBUG -ohci_softc_t   *thesc; -void		ohci_dumpregs __P((ohci_softc_t *)); -void		ohci_dump_tds __P((ohci_soft_td_t *)); -void		ohci_dump_td __P((ohci_soft_td_t *)); -void		ohci_dump_ed __P((ohci_soft_ed_t *)); -#endif - -#if defined(__NetBSD__) -#define OWRITE4(sc, r, x) bus_space_write_4((sc)->iot, (sc)->ioh, (r), (x)) -#define OREAD4(sc, r) bus_space_read_4((sc)->iot, (sc)->ioh, (r)) -#define OREAD2(sc, r) bus_space_read_2((sc)->iot, (sc)->ioh, (r)) -#elif defined(__FreeBSD__) -#define OWRITE4(sc, r, x) *(u_int32_t *) ((sc)->sc_iobase + (r)) = x -#define OREAD4(sc, r) (*(u_int32_t *) ((sc)->sc_iobase + (r))) -#define OREAD2(sc, r) (*(u_int16_t *) ((sc)->sc_iobase + (r))) -#endif - -/* Reverse the bits in a value 0 .. 31 */ -static u_int8_t revbits[OHCI_NO_INTRS] =  -  { 0x00, 0x10, 0x08, 0x18, 0x04, 0x14, 0x0c, 0x1c, -    0x02, 0x12, 0x0a, 0x1a, 0x06, 0x16, 0x0e, 0x1e, -    0x01, 0x11, 0x09, 0x19, 0x05, 0x15, 0x0d, 0x1d, -    0x03, 0x13, 0x0b, 0x1b, 0x07, 0x17, 0x0f, 0x1f }; - -struct ohci_pipe { -	struct usbd_pipe pipe; -	ohci_soft_ed_t *sed; -	ohci_soft_td_t *tail; -	/* Info needed for different pipe kinds. */ -	union { -		/* Control pipe */ -		struct { -			usb_dma_t datadma; -			usb_dma_t reqdma; -			u_int length; -			ohci_soft_td_t *setup, *xfer, *stat; -		} ctl; -		/* Interrupt pipe */ -		struct { -			usb_dma_t datadma; -			int nslots; -			int pos; -		} intr; -		/* Bulk pipe */ -		struct { -			usb_dma_t datadma; -			u_int length; -		} bulk; -	} u; -}; - -#define OHCI_INTR_ENDPT 1 - -struct usbd_methods ohci_root_ctrl_methods = {	 -	ohci_root_ctrl_transfer, -	ohci_root_ctrl_start, -	ohci_root_ctrl_abort, -	ohci_root_ctrl_close, -	0, -}; - -struct usbd_methods ohci_root_intr_methods = {	 -	ohci_root_intr_transfer, -	ohci_root_intr_start, -	ohci_root_intr_abort, -	ohci_root_intr_close, -	0, -}; - -struct usbd_methods ohci_device_ctrl_methods = {	 -	ohci_device_ctrl_transfer, -	ohci_device_ctrl_start, -	ohci_device_ctrl_abort, -	ohci_device_ctrl_close, -	0, -}; - -struct usbd_methods ohci_device_intr_methods = {	 -	ohci_device_intr_transfer, -	ohci_device_intr_start, -	ohci_device_intr_abort, -	ohci_device_intr_close, -}; - -struct usbd_methods ohci_device_bulk_methods = {	 -	ohci_device_bulk_transfer, -	ohci_device_bulk_start, -	ohci_device_bulk_abort, -	ohci_device_bulk_close, -	0, -}; - -ohci_soft_ed_t * -ohci_alloc_sed(sc) -	ohci_softc_t *sc; -{ -	ohci_soft_ed_t *sed; -	usbd_status r; -	int i, offs; -	usb_dma_t dma; - -	if (!sc->sc_freeeds) { -		DPRINTFN(2, ("ohci_alloc_sed: allocating chunk\n")); -		sed = malloc(sizeof(ohci_soft_ed_t) * OHCI_ED_CHUNK,  -			     M_USBDEV, M_NOWAIT); -		if (!sed) -			return 0; -		r = usb_allocmem(sc->sc_dmatag, OHCI_ED_SIZE * OHCI_ED_CHUNK, -				 OHCI_ED_ALIGN, &dma); -		if (r != USBD_NORMAL_COMPLETION) { -			free(sed, M_USBDEV); -			return 0; -		} -		for(i = 0; i < OHCI_ED_CHUNK; i++, sed++) { -			offs = i * OHCI_ED_SIZE; -			sed->physaddr = DMAADDR(&dma) + offs; -			sed->ed = (ohci_ed_t *) -					((char *)KERNADDR(&dma) + offs); -			sed->next = sc->sc_freeeds; -			sc->sc_freeeds = sed; -		} -	} -	sed = sc->sc_freeeds; -	sc->sc_freeeds = sed->next; -	memset(sed->ed, 0, OHCI_ED_SIZE); -	sed->next = 0; -	return sed; -} - -void -ohci_free_sed(sc, sed) -	ohci_softc_t *sc; -	ohci_soft_ed_t *sed; -{ -	sed->next = sc->sc_freeeds; -	sc->sc_freeeds = sed; -} - -ohci_soft_td_t * -ohci_alloc_std(sc) -	ohci_softc_t *sc; -{ -	ohci_soft_td_t *std; -	usbd_status r; -	int i, offs; -	usb_dma_t dma; - -	if (!sc->sc_freetds) { -		DPRINTFN(2, ("ohci_alloc_std: allocating chunk\n")); -		std = malloc(sizeof(ohci_soft_td_t) * OHCI_TD_CHUNK,  -			     M_USBDEV, M_NOWAIT); -		if (!std) -			return 0; -		r = usb_allocmem(sc->sc_dmatag, OHCI_TD_SIZE * OHCI_TD_CHUNK, -				 OHCI_TD_ALIGN, &dma); -		if (r != USBD_NORMAL_COMPLETION) { -			free(std, M_USBDEV); -			return 0; -		} -		for(i = 0; i < OHCI_TD_CHUNK; i++, std++) { -			offs = i * OHCI_TD_SIZE; -			std->physaddr = DMAADDR(&dma) + offs; -			std->td = (ohci_td_t *) -					((char *)KERNADDR(&dma) + offs); -			std->nexttd = sc->sc_freetds; -			sc->sc_freetds = std; -		} -	} -	std = sc->sc_freetds; -	sc->sc_freetds = std->nexttd; -	memset(std->td, 0, OHCI_TD_SIZE); -	std->nexttd = 0; -	return (std); -} - -void -ohci_free_std(sc, std) -	ohci_softc_t *sc; -	ohci_soft_td_t *std; -{ -	std->nexttd = sc->sc_freetds; -	sc->sc_freetds = std; -} - -usbd_status -ohci_init(sc) -	ohci_softc_t *sc; -{ -	ohci_soft_ed_t *sed, *psed; -	usbd_status r; -	int rev; -	int i; -	u_int32_t s, ctl, ival, hcr, fm, per; - -	DPRINTF(("ohci_init: start\n")); -	rev = OREAD4(sc, OHCI_REVISION); -	printf("%s: OHCI version %d.%d%s\n", USBDEVNAME(sc->sc_bus.bdev), -	       OHCI_REV_HI(rev), OHCI_REV_LO(rev), -	       OHCI_REV_LEGACY(rev) ? ", legacy support" : ""); -	if (OHCI_REV_HI(rev) != 1 || OHCI_REV_LO(rev) != 0) { -		printf("%s: unsupported OHCI revision\n",  -		       USBDEVNAME(sc->sc_bus.bdev)); -		return (USBD_INVAL); -	} - -	for (i = 0; i < OHCI_HASH_SIZE; i++) -		LIST_INIT(&sc->sc_hash_tds[i]); - -	/* Allocate the HCCA area. */ -	r = usb_allocmem(sc->sc_dmatag, OHCI_HCCA_SIZE,  -			 OHCI_HCCA_ALIGN, &sc->sc_hccadma); -	if (r != USBD_NORMAL_COMPLETION) -		return (r); -	sc->sc_hcca = (struct ohci_hcca *)KERNADDR(&sc->sc_hccadma); -	memset(sc->sc_hcca, 0, OHCI_HCCA_SIZE); - -	sc->sc_eintrs = OHCI_NORMAL_INTRS; - -	sc->sc_ctrl_head = ohci_alloc_sed(sc); -	if (!sc->sc_ctrl_head) { -		r = USBD_NOMEM; -		goto bad1; -	} -	sc->sc_ctrl_head->ed->ed_flags |= LE(OHCI_ED_SKIP); -	sc->sc_bulk_head = ohci_alloc_sed(sc); -	if (!sc->sc_bulk_head) { -		r = USBD_NOMEM; -		goto bad2; -	} -	sc->sc_bulk_head->ed->ed_flags |= LE(OHCI_ED_SKIP); - -	/* Allocate all the dummy EDs that make up the interrupt tree. */ -	for (i = 0; i < OHCI_NO_EDS; i++) { -		sed = ohci_alloc_sed(sc); -		if (!sed) { -			while (--i >= 0) -				ohci_free_sed(sc, sc->sc_eds[i]); -			r = USBD_NOMEM; -			goto bad3; -		} -		/* All ED fields are set to 0. */ -		sc->sc_eds[i] = sed; -		sed->ed->ed_flags |= LE(OHCI_ED_SKIP); -		if (i != 0) { -			psed = sc->sc_eds[(i-1) / 2]; -			sed->next = psed; -			sed->ed->ed_nexted = LE(psed->physaddr); -		} -	} -	/*  -	 * Fill HCCA interrupt table.  The bit reversal is to get -	 * the tree set up properly to spread the interrupts. -	 */ -	for (i = 0; i < OHCI_NO_INTRS; i++) -		sc->sc_hcca->hcca_interrupt_table[revbits[i]] =  -			LE(sc->sc_eds[OHCI_NO_EDS-OHCI_NO_INTRS+i]->physaddr); - -	/* Determine in what context we are running. */ -	ctl = OREAD4(sc, OHCI_CONTROL); -	if (ctl & OHCI_IR) { -		/* SMM active, request change */ -		DPRINTF(("ohci_init: SMM active, request owner change\n")); -		s = OREAD4(sc, OHCI_COMMAND_STATUS); -		OWRITE4(sc, OHCI_COMMAND_STATUS, s | OHCI_OCR); -		for (i = 0; i < 100 && (ctl & OHCI_IR); i++) { -			delay(1000); -			ctl = OREAD4(sc, OHCI_CONTROL); -		} -		if ((ctl & OHCI_IR) == 0) { -			printf("%s: SMM does not respond, resetting\n", -			       USBDEVNAME(sc->sc_bus.bdev)); -			OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET); -			goto reset; -		} -	} else if ((ctl & OHCI_HCFS_MASK) != OHCI_HCFS_RESET) { -		/* BIOS started controller. */ -		DPRINTF(("ohci_init: BIOS active\n")); -		if ((ctl & OHCI_HCFS_MASK) != OHCI_HCFS_OPERATIONAL) { -			OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_OPERATIONAL); -			delay(USB_RESUME_DELAY * 1000); -		} -	} else { -		DPRINTF(("ohci_init: cold started\n")); -	reset: -		/* Controller was cold started. */ -		delay(USB_BUS_RESET_DELAY * 1000); -	} - -	/* -	 * This reset should not be necessary according to the OHCI spec, but -	 * without it some controllers do not start. -	 */ -	DPRINTF(("%s: resetting\n", USBDEVNAME(sc->sc_bus.bdev))); -	OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET); -	delay(USB_BUS_RESET_DELAY * 1000); - -	/* We now own the host controller and the bus has been reset. */ -	ival = OHCI_GET_IVAL(OREAD4(sc, OHCI_FM_INTERVAL)); - -	OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_HCR); /* Reset HC */ -	/* Nominal time for a reset is 10 us. */ -	for (i = 0; i < 10; i++) { -		delay(10); -		hcr = OREAD4(sc, OHCI_COMMAND_STATUS) & OHCI_HCR; -		if (!hcr) -			break; -	} -	if (hcr) { -		printf("%s: reset timeout\n", USBDEVNAME(sc->sc_bus.bdev)); -		r = USBD_IOERROR; -		goto bad3; -	} -#ifdef USB_DEBUG -	thesc = sc; -	if (ohcidebug > 15) -		ohci_dumpregs(sc); -#endif - -	/* The controller is now in suspend state, we have 2ms to finish. */ - -	/* Set up HC registers. */ -	OWRITE4(sc, OHCI_HCCA, DMAADDR(&sc->sc_hccadma)); -	OWRITE4(sc, OHCI_CONTROL_HEAD_ED, sc->sc_ctrl_head->physaddr); -	OWRITE4(sc, OHCI_BULK_HEAD_ED, sc->sc_bulk_head->physaddr); -	OWRITE4(sc, OHCI_INTERRUPT_DISABLE, OHCI_ALL_INTRS); -	OWRITE4(sc, OHCI_INTERRUPT_ENABLE, sc->sc_eintrs | OHCI_MIE); -	ctl = OREAD4(sc, OHCI_CONTROL); -	ctl &= ~(OHCI_CBSR_MASK | OHCI_LES | OHCI_HCFS_MASK | OHCI_IR); -	ctl |= OHCI_PLE | OHCI_IE | OHCI_CLE | OHCI_BLE | -		OHCI_RATIO_1_4 | OHCI_HCFS_OPERATIONAL; -	/* And finally start it! */ -	OWRITE4(sc, OHCI_CONTROL, ctl); - -	/* -	 * The controller is now OPERATIONAL.  Set a some final -	 * registers that should be set earlier, but that the -	 * controller ignores when in the SUSPEND state. -	 */ -	fm = (OREAD4(sc, OHCI_FM_INTERVAL) & OHCI_FIT) ^ OHCI_FIT; -	fm |= OHCI_FSMPS(ival) | ival; -	OWRITE4(sc, OHCI_FM_INTERVAL, fm); -	per = OHCI_PERIODIC(ival); /* 90% periodic */ -	OWRITE4(sc, OHCI_PERIODIC_START, per); - -	OWRITE4(sc, OHCI_RH_STATUS, OHCI_LPSC);	/* Enable port power */ - -	sc->sc_noport = OHCI_GET_NDP(OREAD4(sc, OHCI_RH_DESCRIPTOR_A)); - -#ifdef USB_DEBUG -	if (ohcidebug > 5) -		ohci_dumpregs(sc); -#endif -	 -	/* Set up the bus struct. */ -	sc->sc_bus.open_pipe = ohci_open; -	sc->sc_bus.pipe_size = sizeof(struct ohci_pipe); -	sc->sc_bus.do_poll = ohci_poll; - -	return (USBD_NORMAL_COMPLETION); - - bad3: -	ohci_free_sed(sc, sc->sc_ctrl_head); - bad2: -	ohci_free_sed(sc, sc->sc_bulk_head); - bad1: -	usb_freemem(sc->sc_dmatag, &sc->sc_hccadma); -	return (r); -} - -#ifdef USB_DEBUG -void ohcidump(void); -void ohcidump(void) { ohci_dumpregs(thesc); } - -void -ohci_dumpregs(sc) -	ohci_softc_t *sc; -{ -	printf("ohci_dumpregs: rev=0x%08x control=0x%08x command=0x%08x\n", -	       OREAD4(sc, OHCI_REVISION), -	       OREAD4(sc, OHCI_CONTROL), -	       OREAD4(sc, OHCI_COMMAND_STATUS)); -	printf("               intrstat=0x%08x intre=0x%08x intrd=0x%08x\n", -	       OREAD4(sc, OHCI_INTERRUPT_STATUS), -	       OREAD4(sc, OHCI_INTERRUPT_ENABLE), -	       OREAD4(sc, OHCI_INTERRUPT_DISABLE)); -	printf("               hcca=0x%08x percur=0x%08x ctrlhd=0x%08x\n", -	       OREAD4(sc, OHCI_HCCA), -	       OREAD4(sc, OHCI_PERIOD_CURRENT_ED), -	       OREAD4(sc, OHCI_CONTROL_HEAD_ED)); -	printf("               ctrlcur=0x%08x bulkhd=0x%08x bulkcur=0x%08x\n", -	       OREAD4(sc, OHCI_CONTROL_CURRENT_ED), -	       OREAD4(sc, OHCI_BULK_HEAD_ED), -	       OREAD4(sc, OHCI_BULK_CURRENT_ED)); -	printf("               done=0x%08x fmival=0x%08x fmrem=0x%08x\n", -	       OREAD4(sc, OHCI_DONE_HEAD), -	       OREAD4(sc, OHCI_FM_INTERVAL), -	       OREAD4(sc, OHCI_FM_REMAINING)); -	printf("               fmnum=0x%08x perst=0x%08x lsthrs=0x%08x\n", -	       OREAD4(sc, OHCI_FM_NUMBER), -	       OREAD4(sc, OHCI_PERIODIC_START), -	       OREAD4(sc, OHCI_LS_THRESHOLD)); -	printf("               desca=0x%08x descb=0x%08x stat=0x%08x\n", -	       OREAD4(sc, OHCI_RH_DESCRIPTOR_A), -	       OREAD4(sc, OHCI_RH_DESCRIPTOR_B), -	       OREAD4(sc, OHCI_RH_STATUS)); -	printf("               port1=0x%08x port2=0x%08x\n", -	       OREAD4(sc, OHCI_RH_PORT_STATUS(1)), -	       OREAD4(sc, OHCI_RH_PORT_STATUS(2))); -	printf("         HCCA: frame_number=0x%04x done_head=0x%08x\n", -	       LE(sc->sc_hcca->hcca_frame_number), -	       LE(sc->sc_hcca->hcca_done_head)); -} -#endif - -int -ohci_intr(p) -	void *p; -{ -	ohci_softc_t *sc = p; -	u_int32_t intrs = 0, eintrs; -	ohci_physaddr_t done; - -	/* In case the interrupt occurs before initialization has completed. */ -	if (sc == NULL || sc->sc_hcca == NULL) {	/* NWH added sc==0 */ -#ifdef DIAGNOSTIC -		printf("ohci_intr: sc->sc_hcca == NULL\n"); -#endif -		return (0); -	} - -	done = LE(sc->sc_hcca->hcca_done_head); -	if (done != 0) { -		sc->sc_hcca->hcca_done_head = 0; -		if (done & ~OHCI_DONE_INTRS) -			intrs = OHCI_WDH; -		if (done & OHCI_DONE_INTRS) -			intrs |= OREAD4(sc, OHCI_INTERRUPT_STATUS); -	} else -		intrs = OREAD4(sc, OHCI_INTERRUPT_STATUS); -	if (!intrs) -		return (0); -	intrs &= ~OHCI_MIE; -	OWRITE4(sc, OHCI_INTERRUPT_STATUS, intrs); /* Acknowledge */ -	eintrs = intrs & sc->sc_eintrs; -	if (!eintrs) -		return (0); - -	sc->sc_intrs++; -	DPRINTFN(7, ("ohci_intr: sc=%p intrs=%x(%x) eintr=%x\n",  -		     sc, (u_int)intrs, OREAD4(sc, OHCI_INTERRUPT_STATUS), -		     (u_int)eintrs)); - -	if (eintrs & OHCI_SO) { -		printf("%s: scheduling overrun\n",USBDEVNAME(sc->sc_bus.bdev)); -		/* XXX do what */ -		intrs &= ~OHCI_SO; -	} -	if (eintrs & OHCI_WDH) { -		ohci_process_done(sc, done &~ OHCI_DONE_INTRS); -		intrs &= ~OHCI_WDH; -	} -	if (eintrs & OHCI_RD) { -		/* XXX process resume detect */ -	} -	if (eintrs & OHCI_UE) { -		printf("%s: unrecoverable error, controller halted\n", -		       USBDEVNAME(sc->sc_bus.bdev)); -		OWRITE4(sc, OHCI_CONTROL, OHCI_HCFS_RESET); -		/* XXX what else */ -	} -	if (eintrs & OHCI_RHSC) { -		ohci_rhsc(sc, sc->sc_intrreqh); -		intrs &= ~OHCI_RHSC; - -		/*  -		 * Disable RHSC interrupt for now, because it will be -		 * on until the port has been reset. -		 */ -		ohci_rhsc_able(sc, 0); -	} - -	/* Block unprocessed interrupts. XXX */ -	OWRITE4(sc, OHCI_INTERRUPT_DISABLE, intrs); -	sc->sc_eintrs &= ~intrs; - -	return (1); -} - -void -ohci_rhsc_able(sc, on) -	ohci_softc_t *sc; -	int on; -{ -	DPRINTFN(4, ("ohci_rhsc_able: on=%d\n", on)); -	if (on) { -		sc->sc_eintrs |= OHCI_RHSC; -		OWRITE4(sc, OHCI_INTERRUPT_ENABLE, OHCI_RHSC); -	} else { -		sc->sc_eintrs &= ~OHCI_RHSC; -		OWRITE4(sc, OHCI_INTERRUPT_DISABLE, OHCI_RHSC); -	} -} - -#ifdef USB_DEBUG -char *ohci_cc_strs[] = { -	"NO_ERROR", -	"CRC", -	"BIT_STUFFING", -	"DATA_TOGGLE_MISMATCH", -	"STALL", -	"DEVICE_NOT_RESPONDING", -	"PID_CHECK_FAILURE", -	"UNEXPECTED_PID", -	"DATA_OVERRUN", -	"DATA_UNDERRUN", -	"BUFFER_OVERRUN", -	"BUFFER_UNDERRUN", -	"NOT_ACCESSED", -}; -#endif - -void -ohci_process_done(sc, done) -	ohci_softc_t *sc; -	ohci_physaddr_t done; -{ -	ohci_soft_td_t *std = NULL, *sdone; -	usbd_request_handle reqh; -	int len, cc; - -	DPRINTFN(10,("ohci_process_done: done=0x%08lx\n", (u_long)done)); - -	/* Reverse the done list. */ -	for (sdone = 0; done; done = LE(std->td->td_nexttd)) { -		std = ohci_hash_find_td(sc, done); -		std->dnext = sdone; -		sdone = std; -	} - -#ifdef USB_DEBUG -	if (ohcidebug > 10) { -		printf("ohci_process_done: TD done:\n"); -		ohci_dump_tds(sdone); -	} -#endif - -	for (std = sdone; std; std = std->dnext) { -		reqh = std->reqh; -		DPRINTFN(10, ("ohci_process_done: std=%p reqh=%p hcpriv=%p\n", -				std, reqh, reqh->hcpriv)); -		cc = OHCI_TD_GET_CC(LE(std->td->td_flags)); -		if (cc == OHCI_CC_NO_ERROR) { -			if (std->td->td_cbp == 0) -				len = std->len; -			else -				len = LE(std->td->td_be) -  -				      LE(std->td->td_cbp) + 1; -			/*  -			 * Only do a callback on the last stage of a transfer. -			 * Others have hcpriv = 0. -			 */ -			if ((reqh->pipe->endpoint->edesc->bmAttributes &  -			     UE_XFERTYPE) == UE_CONTROL) { -				/* For a control transfer the length is in -				 * the xfer stage */ -				if (reqh->hcpriv == std) { -					reqh->status = USBD_NORMAL_COMPLETION; -					ohci_ii_done(sc, reqh); -				} else -					reqh->actlen = len; -			} else { -				if (reqh->hcpriv == std) { -					reqh->actlen = len; -					reqh->status = USBD_NORMAL_COMPLETION; -					ohci_ii_done(sc, reqh); -				} -			} -		} else { -			ohci_soft_td_t *p, *n; -			struct ohci_pipe *opipe =  -				(struct ohci_pipe *)reqh->pipe; -			DPRINTFN(-1,("ohci_process_done: error cc=%d (%s)\n", -			 OHCI_TD_GET_CC(LE(std->td->td_flags)), -			 ohci_cc_strs[OHCI_TD_GET_CC(LE(std->td->td_flags))])); -			/* -			 * Endpoint is halted.  First unlink all the TDs -			 * belonging to the failed transfer, and then restart -			 * the endpoint. -			 */ -			for (p = std->nexttd; p->reqh == reqh; p = n) { -				n = p->nexttd; -				ohci_hash_rem_td(sc, p); -				ohci_free_std(sc, p); -			} -			/* clear halt */ -			opipe->sed->ed->ed_headp = LE(p->physaddr); -			OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_CLF); -			 -			if (cc == OHCI_CC_STALL) -				reqh->status = USBD_STALLED; -			else -				reqh->status = USBD_IOERROR; -			ohci_ii_done(sc, reqh); -		} -		ohci_hash_rem_td(sc, std); -		ohci_free_std(sc, std); -	} -} - -void -ohci_ii_done(sc, reqh) -	ohci_softc_t *sc; -	usbd_request_handle reqh; -{ -	switch (reqh->pipe->endpoint->edesc->bmAttributes & UE_XFERTYPE) { -	case UE_CONTROL: -		ohci_ctrl_done(sc, reqh); -		usb_start_next(reqh->pipe); -		break; -	case UE_INTERRUPT: -		ohci_intr_done(sc, reqh); -		break; -	case UE_BULK: -		ohci_bulk_done(sc, reqh); -		usb_start_next(reqh->pipe); -		break; -	case UE_ISOCHRONOUS: -		printf("ohci_process_done: ISO done?\n"); -		usb_start_next(reqh->pipe); -		break; -	} - -	/* And finally execute callback. */ -	reqh->xfercb(reqh); -} - -void -ohci_ctrl_done(sc, reqh) -	ohci_softc_t *sc; -	usbd_request_handle reqh; -{ -	struct ohci_pipe *opipe = (struct ohci_pipe *)reqh->pipe; -	u_int len = opipe->u.ctl.length; -	usb_dma_t *dma; - -	DPRINTFN(10,("ohci_ctrl_done: reqh=%p\n", reqh)); - -	if (!reqh->isreq) { -		panic("ohci_ctrl_done: not a request\n"); -		return; -	} - -	if (len != 0) { -		dma = &opipe->u.ctl.datadma; -		if (reqh->request.bmRequestType & UT_READ) -			memcpy(reqh->buffer, KERNADDR(dma), len); -		usb_freemem(sc->sc_dmatag, dma); -	} -	usb_untimeout(ohci_timeout, reqh, reqh->timo_handle); -} - -void -ohci_intr_done(sc, reqh) -	ohci_softc_t *sc; -	usbd_request_handle reqh; -{ -	struct ohci_pipe *opipe = (struct ohci_pipe *)reqh->pipe; -	usb_dma_t *dma; -	ohci_soft_ed_t *sed = opipe->sed; -	ohci_soft_td_t *xfer, *tail; - - -	DPRINTFN(10,("ohci_intr_done: reqh=%p, actlen=%d\n",  -		     reqh, reqh->actlen)); - -	dma = &opipe->u.intr.datadma; -	memcpy(reqh->buffer, KERNADDR(dma), reqh->actlen); - -	if (reqh->pipe->intrreqh == reqh) { -		xfer = opipe->tail; -		tail = ohci_alloc_std(sc); /* XXX should reuse TD */ -		if (!tail) { -			reqh->status = USBD_NOMEM; -			return; -		} -		tail->reqh = 0; -		 -		xfer->td->td_flags = LE( -			OHCI_TD_IN | OHCI_TD_NOCC |  -			OHCI_TD_SET_DI(1) | OHCI_TD_TOGGLE_CARRY); -		if (reqh->flags & USBD_SHORT_XFER_OK) -			xfer->td->td_flags |= LE(OHCI_TD_R); -		xfer->td->td_cbp = LE(DMAADDR(dma)); -		xfer->nexttd = tail; -		xfer->td->td_nexttd = LE(tail->physaddr); -		xfer->td->td_be = LE(LE(xfer->td->td_cbp) + reqh->length - 1); -		xfer->len = reqh->length; -		xfer->reqh = reqh; - -		reqh->hcpriv = xfer; - -		ohci_hash_add_td(sc, xfer); -		sed->ed->ed_tailp = LE(tail->physaddr); -		opipe->tail = tail; -	} else { -		usb_freemem(sc->sc_dmatag, dma); -		usb_start_next(reqh->pipe); -	} -} - -void -ohci_bulk_done(sc, reqh) -	ohci_softc_t *sc; -	usbd_request_handle reqh; -{ -	struct ohci_pipe *opipe = (struct ohci_pipe *)reqh->pipe; -	usb_dma_t *dma; - - -	DPRINTFN(10,("ohci_bulk_done: reqh=%p, actlen=%d\n",  -		     reqh, reqh->actlen)); - -	dma = &opipe->u.bulk.datadma; -	if (reqh->request.bmRequestType & UT_READ) -		memcpy(reqh->buffer, KERNADDR(dma), reqh->actlen); -	usb_freemem(sc->sc_dmatag, dma); -	usb_untimeout(ohci_timeout, reqh, reqh->timo_handle); -} - -void -ohci_rhsc(sc, reqh) -	ohci_softc_t *sc; -	usbd_request_handle reqh; -{ -	usbd_pipe_handle pipe; -	struct ohci_pipe *opipe; -	u_char *p; -	int i, m; -	int hstatus; - -	hstatus = OREAD4(sc, OHCI_RH_STATUS); -	DPRINTF(("ohci_rhsc: sc=%p reqh=%p hstatus=0x%08x\n",  -		 sc, reqh, hstatus)); - -	if (reqh == 0) { -		/* Just ignore the change. */ -		return; -	} - -	pipe = reqh->pipe; -	opipe = (struct ohci_pipe *)pipe; - -	p = KERNADDR(&opipe->u.intr.datadma); -	m = min(sc->sc_noport, reqh->length * 8 - 1); -	memset(p, 0, reqh->length); -	for (i = 1; i <= m; i++) { -		if (OREAD4(sc, OHCI_RH_PORT_STATUS(i)) >> 16) -			p[i/8] |= 1 << (i%8); -	} -	DPRINTF(("ohci_rhsc: change=0x%02x\n", *p)); -	reqh->actlen = reqh->length; -	reqh->status = USBD_NORMAL_COMPLETION; -	reqh->xfercb(reqh); - -	if (reqh->pipe->intrreqh != reqh) { -		sc->sc_intrreqh = 0; -		usb_freemem(sc->sc_dmatag, &opipe->u.intr.datadma); -		usb_start_next(reqh->pipe); -	} -} - -/* - * Wait here until controller claims to have an interrupt. - * Then call ohci_intr and return.  Use timeout to avoid waiting - * too long. - */ -void -ohci_waitintr(sc, reqh) -	ohci_softc_t *sc; -	usbd_request_handle reqh; -{ -	int timo = reqh->timeout; -	int usecs; -	u_int32_t intrs; - -	reqh->status = USBD_IN_PROGRESS; -	for (usecs = timo * 1000000 / hz; usecs > 0; usecs -= 1000) { -		usb_delay_ms(&sc->sc_bus, 1); -		intrs = OREAD4(sc, OHCI_INTERRUPT_STATUS) & sc->sc_eintrs; -		DPRINTFN(15,("ohci_waitintr: 0x%04x\n", intrs)); -#ifdef USB_DEBUG -		if (ohcidebug > 15) -			ohci_dumpregs(sc); -#endif -		if (intrs) { -			ohci_intr(sc); -			if (reqh->status != USBD_IN_PROGRESS) -				return; -		} -	} - -	/* Timeout */ -	DPRINTF(("ohci_waitintr: timeout\n")); -	reqh->status = USBD_TIMEOUT; -	ohci_ii_done(sc, reqh); -	/* XXX should free TD */ -} - -void -ohci_poll(bus) -	struct usbd_bus *bus; -{ -	ohci_softc_t *sc = (ohci_softc_t *)bus; - -	if (OREAD4(sc, OHCI_INTERRUPT_STATUS) & sc->sc_eintrs) -		ohci_intr(sc); -} - -usbd_status -ohci_device_request(reqh) -	usbd_request_handle reqh; -{ -	struct ohci_pipe *opipe = (struct ohci_pipe *)reqh->pipe; -	usb_device_request_t *req = &reqh->request; -	usbd_device_handle dev = opipe->pipe.device; -	ohci_softc_t *sc = (ohci_softc_t *)dev->bus; -	int addr = dev->address; -	ohci_soft_td_t *setup, *xfer = 0, *stat, *next, *tail; -	ohci_soft_ed_t *sed; -	usb_dma_t *dmap; -	int isread; -	int len; -	usbd_status r; -	int s; - -	isread = req->bmRequestType & UT_READ; -	len = UGETW(req->wLength); - -	DPRINTFN(3,("ohci_device_control type=0x%02x, request=0x%02x, " -		    "wValue=0x%04x, wIndex=0x%04x len=%d, addr=%d, endpt=%d\n", -		    req->bmRequestType, req->bRequest, UGETW(req->wValue), -		    UGETW(req->wIndex), len, addr,  -		    opipe->pipe.endpoint->edesc->bEndpointAddress)); - -	setup = opipe->tail; -	stat = ohci_alloc_std(sc); -	if (!stat) { -		r = USBD_NOMEM; -		goto bad1; -	} -	tail = ohci_alloc_std(sc); -	if (!tail) { -		r = USBD_NOMEM; -		goto bad2; -	} -	tail->reqh = 0; - -	sed = opipe->sed; -	dmap = &opipe->u.ctl.datadma; -	opipe->u.ctl.length = len; - -	/* Update device address and length since they may have changed. */ -	/* XXX This only needs to be done once, but it's too early in open. */ -	sed->ed->ed_flags = LE( -	 (LE(sed->ed->ed_flags) & ~(OHCI_ED_ADDRMASK | OHCI_ED_MAXPMASK)) | -	 OHCI_ED_SET_FA(addr) | -	 OHCI_ED_SET_MAXP(UGETW(opipe->pipe.endpoint->edesc->wMaxPacketSize))); - -	/* Set up data transaction */ -	if (len != 0) { -		xfer = ohci_alloc_std(sc); -		if (!xfer) { -			r = USBD_NOMEM; -			goto bad3; -		} -		r = usb_allocmem(sc->sc_dmatag, len, 0, dmap); -		if (r != USBD_NORMAL_COMPLETION) -			goto bad4; -		xfer->td->td_flags = LE( -			(isread ? OHCI_TD_IN : OHCI_TD_OUT) | OHCI_TD_NOCC | -			OHCI_TD_TOGGLE_1 | OHCI_TD_NOINTR | -			(reqh->flags & USBD_SHORT_XFER_OK ? OHCI_TD_R : 0)); -		xfer->td->td_cbp = LE(DMAADDR(dmap)); -		xfer->nexttd = stat; -		xfer->td->td_nexttd = LE(stat->physaddr); -		xfer->td->td_be = LE(LE(xfer->td->td_cbp) + len - 1); -		xfer->len = len; -		xfer->reqh = reqh; - -		next = xfer; -	} else -		next = stat; - -	memcpy(KERNADDR(&opipe->u.ctl.reqdma), req, sizeof *req); -	if (!isread && len != 0) -		memcpy(KERNADDR(dmap), reqh->buffer, len); - -	setup->td->td_flags = LE(OHCI_TD_SETUP | OHCI_TD_NOCC | -				 OHCI_TD_TOGGLE_0 | OHCI_TD_NOINTR); -	setup->td->td_cbp = LE(DMAADDR(&opipe->u.ctl.reqdma)); -	setup->nexttd = next; -	setup->td->td_nexttd = LE(next->physaddr); -	setup->td->td_be = LE(LE(setup->td->td_cbp) + sizeof *req - 1); -	setup->len = 0;		/* XXX The number of byte we count */ -	setup->reqh = reqh; - -	stat->td->td_flags = LE( -		(isread ? OHCI_TD_OUT : OHCI_TD_IN) | OHCI_TD_NOCC | -		OHCI_TD_TOGGLE_1 | OHCI_TD_SET_DI(1)); -	stat->td->td_cbp = 0; -	stat->nexttd = tail; -	stat->td->td_nexttd = LE(tail->physaddr); -	stat->td->td_be = 0; -	stat->len = 0; -	stat->reqh = reqh; - -	reqh->hcpriv = stat; - -#if USB_DEBUG -	if (ohcidebug > 5) { -		printf("ohci_device_request:\n"); -		ohci_dump_ed(sed); -		ohci_dump_tds(setup); -	} -#endif - -	/* Insert ED in schedule */ -	s = splusb(); -	ohci_hash_add_td(sc, setup); -	if (len != 0) -		ohci_hash_add_td(sc, xfer); -	ohci_hash_add_td(sc, stat); -	sed->ed->ed_tailp = LE(tail->physaddr); -	opipe->tail = tail; -	OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_CLF); -	if (reqh->timeout && !sc->sc_bus.use_polling) { -                usb_timeout(ohci_timeout, reqh, -			    MS_TO_TICKS(reqh->timeout), reqh->timo_handle); -	} -	splx(s); - -#if USB_DEBUG -	if (ohcidebug > 5) { -		delay(5000); -		printf("ohci_device_request: status=%x\n", -		       OREAD4(sc, OHCI_COMMAND_STATUS)); -		ohci_dump_ed(sed); -		ohci_dump_tds(setup); -	} -#endif - -	return (USBD_NORMAL_COMPLETION); - - bad4: -	ohci_free_std(sc, xfer); - bad3: -	ohci_free_std(sc, tail); - bad2: -	ohci_free_std(sc, stat); - bad1: -	return (r); -} - -/* - * Add an ED to the schedule.  Called at splusb(). - */ -void -ohci_add_ed(sed, head) -	ohci_soft_ed_t *sed;  -	ohci_soft_ed_t *head;  -{ -	sed->next = head->next; -	sed->ed->ed_nexted = head->ed->ed_nexted; -	head->next = sed; -	head->ed->ed_nexted = LE(sed->physaddr); -} - -/* - * Remove an ED from the schedule.  Called at splusb(). - */ -void -ohci_rem_ed(sed, head) -	ohci_soft_ed_t *sed;  -	ohci_soft_ed_t *head;  -{ -	ohci_soft_ed_t *p;  - -	/* XXX */ -	for (p = head; p && p->next != sed; p = p->next) -		; -	if (!p) -		panic("ohci_rem_ed: ED not found\n"); -	p->next = sed->next; -	p->ed->ed_nexted = sed->ed->ed_nexted; -} - -/* - * When a transfer is completed the TD is added to the done queue by - * the host controller.  This queue is the processed by software. - * Unfortunately the queue contains the physical address of the TD - * and we have no simple way to translate this back to a kernel address. - * To make the translation possible (and fast) we use a hash table of - * TDs currently in the schedule.  The physical address is used as the - * hash value. - */ - -#define HASH(a) (((a) >> 4) % OHCI_HASH_SIZE) -/* Called at splusb() */ -void -ohci_hash_add_td(sc, std) -	ohci_softc_t *sc; -	ohci_soft_td_t *std; -{ -	int h = HASH(std->physaddr); - -	LIST_INSERT_HEAD(&sc->sc_hash_tds[h], std, hnext); -} - -/* Called at splusb() */ -void -ohci_hash_rem_td(sc, std) -	ohci_softc_t *sc; -	ohci_soft_td_t *std; -{ -	LIST_REMOVE(std, hnext); -} - -ohci_soft_td_t * -ohci_hash_find_td(sc, a) -	ohci_softc_t *sc; -	ohci_physaddr_t a; -{ -	int h = HASH(a); -	ohci_soft_td_t *std; - -	for (std = LIST_FIRST(&sc->sc_hash_tds[h]);  -	     std != 0;  -	     std = LIST_NEXT(std, hnext)) -		if (std->physaddr == a) -			return (std); -	panic("ohci_hash_find_td: addr 0x%08lx not found\n", (u_long)a); -} - -void -ohci_timeout(addr) -	void *addr; -{ -#if 0 -	usbd_request_handle *reqh = addr; -	int s; - -	DPRINTF(("ohci_timeout: reqh=%p\n", reqh)); -	s = splusb(); -	/* XXX need to inactivate TD before calling interrupt routine */ -	ohci_XXX_done(reqh); -	splx(s); -#endif -} - -#ifdef USB_DEBUG -void -ohci_dump_tds(std) -	ohci_soft_td_t *std; -{ -	for (; std; std = std->nexttd) -		ohci_dump_td(std); -} - -void -ohci_dump_td(std) -	ohci_soft_td_t *std; -{ -	printf("TD(%p) at %08lx: %b delay=%d ec=%d cc=%d\ncbp=0x%08lx " -	       "nexttd=0x%08lx be=0x%08lx\n",  -	       std, (u_long)std->physaddr, -	       (int)LE(std->td->td_flags), -	       "\20\23R\24OUT\25IN\31TOG1\32SETTOGGLE", -	       OHCI_TD_GET_DI(LE(std->td->td_flags)), -	       OHCI_TD_GET_EC(LE(std->td->td_flags)), -	       OHCI_TD_GET_CC(LE(std->td->td_flags)), -	       (u_long)LE(std->td->td_cbp), -	       (u_long)LE(std->td->td_nexttd), (u_long)LE(std->td->td_be)); -} - -void -ohci_dump_ed(sed) -	ohci_soft_ed_t *sed; -{ -	printf("ED(%p) at %08lx: addr=%d endpt=%d maxp=%d %b\ntailp=0x%08lx " -	       "headp=%b nexted=0x%08lx\n", -	       sed, (u_long)sed->physaddr,  -	       OHCI_ED_GET_FA(LE(sed->ed->ed_flags)), -	       OHCI_ED_GET_EN(LE(sed->ed->ed_flags)), -	       OHCI_ED_GET_MAXP(LE(sed->ed->ed_flags)), -	       (int)LE(sed->ed->ed_flags), -	       "\20\14OUT\15IN\16LOWSPEED\17SKIP\20ISO", -	       (u_long)LE(sed->ed->ed_tailp), -	       (int)LE(sed->ed->ed_headp), "\20\1HALT\2CARRY", -	       (u_long)LE(sed->ed->ed_nexted)); -} -#endif - -usbd_status -ohci_open(pipe) -	usbd_pipe_handle pipe; -{ -	usbd_device_handle dev = pipe->device; -	ohci_softc_t *sc = (ohci_softc_t *)dev->bus; -	usb_endpoint_descriptor_t *ed = pipe->endpoint->edesc; -	struct ohci_pipe *opipe = (struct ohci_pipe *)pipe; -	u_int8_t addr = dev->address; -	ohci_soft_ed_t *sed; -	ohci_soft_td_t *std; -	usbd_status r; -	int s; - -	DPRINTFN(1, ("ohci_open: pipe=%p, addr=%d, endpt=%d (%d)\n", -		     pipe, addr, ed->bEndpointAddress, sc->sc_addr)); -	if (addr == sc->sc_addr) { -		switch (ed->bEndpointAddress) { -		case USB_CONTROL_ENDPOINT: -			pipe->methods = &ohci_root_ctrl_methods; -			break; -		case UE_IN | OHCI_INTR_ENDPT: -			pipe->methods = &ohci_root_intr_methods; -			break; -		default: -			return (USBD_INVAL); -		} -	} else { -		sed = ohci_alloc_sed(sc); -		if (sed == 0) -			goto bad0; -	        std = ohci_alloc_std(sc); -		if (std == 0) -			goto bad1; -		opipe->sed = sed; -		opipe->tail = std; -		sed->ed->ed_flags = LE( -			OHCI_ED_SET_FA(addr) |  -			OHCI_ED_SET_EN(ed->bEndpointAddress) | -			OHCI_ED_DIR_TD |  -			(dev->lowspeed ? OHCI_ED_SPEED : 0) |  -			((ed->bmAttributes & UE_XFERTYPE) == UE_ISOCHRONOUS ? -			 OHCI_ED_FORMAT_ISO : OHCI_ED_FORMAT_GEN) | -			OHCI_ED_SET_MAXP(UGETW(ed->wMaxPacketSize))); -		sed->ed->ed_headp = sed->ed->ed_tailp = LE(std->physaddr); - -		switch (ed->bmAttributes & UE_XFERTYPE) { -		case UE_CONTROL: -			pipe->methods = &ohci_device_ctrl_methods; -			r = usb_allocmem(sc->sc_dmatag,  -					 sizeof(usb_device_request_t),  -					 0, &opipe->u.ctl.reqdma); -			if (r != USBD_NORMAL_COMPLETION) -				goto bad; -			s = splusb(); -			ohci_add_ed(sed, sc->sc_ctrl_head); -			splx(s); -			break; -		case UE_INTERRUPT: -			pipe->methods = &ohci_device_intr_methods; -			return (ohci_device_setintr(sc, opipe, ed->bInterval)); -		case UE_ISOCHRONOUS: -			printf("ohci_open: open iso unimplemented\n"); -			return (USBD_XXX); -		case UE_BULK: -			pipe->methods = &ohci_device_bulk_methods; -			s = splusb(); -			ohci_add_ed(sed, sc->sc_bulk_head); -			splx(s); -			break; -		} -	} -	return (USBD_NORMAL_COMPLETION); - - bad: -	ohci_free_std(sc, std); - bad1: -	ohci_free_sed(sc, sed); - bad0: -	return (USBD_NOMEM); -	 -} - -/* - * Data structures and routines to emulate the root hub. - */ -usb_device_descriptor_t ohci_devd = { -	USB_DEVICE_DESCRIPTOR_SIZE, -	UDESC_DEVICE,		/* type */ -	{0x00, 0x01},		/* USB version */ -	UCLASS_HUB,		/* class */ -	USUBCLASS_HUB,		/* subclass */ -	0,			/* protocol */ -	64,			/* max packet */ -	{0},{0},{0x00,0x01},	/* device id */ -	1,2,0,			/* string indicies */ -	1			/* # of configurations */ -}; - -usb_config_descriptor_t ohci_confd = { -	USB_CONFIG_DESCRIPTOR_SIZE, -	UDESC_CONFIG, -	{USB_CONFIG_DESCRIPTOR_SIZE + -	 USB_INTERFACE_DESCRIPTOR_SIZE + -	 USB_ENDPOINT_DESCRIPTOR_SIZE}, -	1, -	1, -	0, -	UC_SELF_POWERED, -	0			/* max power */ -}; - -usb_interface_descriptor_t ohci_ifcd = { -	USB_INTERFACE_DESCRIPTOR_SIZE, -	UDESC_INTERFACE, -	0, -	0, -	1, -	UCLASS_HUB, -	USUBCLASS_HUB, -	0, -	0 -}; - -usb_endpoint_descriptor_t ohci_endpd = { -	USB_ENDPOINT_DESCRIPTOR_SIZE, -	UDESC_ENDPOINT, -	UE_IN | OHCI_INTR_ENDPT, -	UE_INTERRUPT, -	{8, 0},			/* max packet */ -	255 -}; - -usb_hub_descriptor_t ohci_hubd = { -	USB_HUB_DESCRIPTOR_SIZE, -	UDESC_HUB, -	0, -	{0,0}, -	0, -	0, -	{0}, -}; - -int -ohci_str(p, l, s) -	usb_string_descriptor_t *p; -	int l; -	char *s; -{ -	int i; - -	if (l == 0) -		return (0); -	p->bLength = 2 * strlen(s) + 2; -	if (l == 1) -		return (1); -	p->bDescriptorType = UDESC_STRING; -	l -= 2; -	for (i = 0; s[i] && l > 1; i++, l -= 2) -		USETW2(p->bString[i], 0, s[i]); -	return (2*i+2); -} - -/* - * Simulate a hardware hub by handling all the necessary requests. - */ -usbd_status -ohci_root_ctrl_transfer(reqh) -	usbd_request_handle reqh; -{ -	int s; -	usbd_status r; - -	s = splusb(); -	r = usb_insert_transfer(reqh); -	splx(s); -	if (r != USBD_NORMAL_COMPLETION) -		return (r); -	else -		return (ohci_root_ctrl_start(reqh)); -} - -usbd_status -ohci_root_ctrl_start(reqh) -	usbd_request_handle reqh; -{ -	ohci_softc_t *sc = (ohci_softc_t *)reqh->pipe->device->bus; -	usb_device_request_t *req; -	void *buf; -	int port, i; -	int len, value, index, l, totlen = 0; -	usb_port_status_t ps; -	usb_hub_descriptor_t hubd; -	usbd_status r; -	u_int32_t v; - -	if (!reqh->isreq) -		/* XXX panic */ -		return (USBD_INVAL); -	req = &reqh->request; -	buf = reqh->buffer; - -	DPRINTFN(4,("ohci_root_ctrl_control type=0x%02x request=%02x\n",  -		    req->bmRequestType, req->bRequest)); - -	len = UGETW(req->wLength); -	value = UGETW(req->wValue); -	index = UGETW(req->wIndex); -#define C(x,y) ((x) | ((y) << 8)) -	switch(C(req->bRequest, req->bmRequestType)) { -	case C(UR_CLEAR_FEATURE, UT_WRITE_DEVICE): -	case C(UR_CLEAR_FEATURE, UT_WRITE_INTERFACE): -	case C(UR_CLEAR_FEATURE, UT_WRITE_ENDPOINT): -		/*  -		 * DEVICE_REMOTE_WAKEUP and ENDPOINT_HALT are no-ops -		 * for the integrated root hub. -		 */ -		break; -	case C(UR_GET_CONFIG, UT_READ_DEVICE): -		if (len > 0) { -			*(u_int8_t *)buf = sc->sc_conf; -			totlen = 1; -		} -		break; -	case C(UR_GET_DESCRIPTOR, UT_READ_DEVICE): -		DPRINTFN(8,("ohci_root_ctrl_control wValue=0x%04x\n", value)); -		switch(value >> 8) { -		case UDESC_DEVICE: -			if ((value & 0xff) != 0) { -				r = USBD_IOERROR; -				goto ret; -			} -			totlen = l = min(len, USB_DEVICE_DESCRIPTOR_SIZE); -			memcpy(buf, &ohci_devd, l); -			break; -		case UDESC_CONFIG: -			if ((value & 0xff) != 0) { -				r = USBD_IOERROR; -				goto ret; -			} -			totlen = l = min(len, USB_CONFIG_DESCRIPTOR_SIZE); -			memcpy(buf, &ohci_confd, l); -			buf = (char *)buf + l; -			len -= l; -			l = min(len, USB_INTERFACE_DESCRIPTOR_SIZE); -			totlen += l; -			memcpy(buf, &ohci_ifcd, l); -			buf = (char *)buf + l; -			len -= l; -			l = min(len, USB_ENDPOINT_DESCRIPTOR_SIZE); -			totlen += l; -			memcpy(buf, &ohci_endpd, l); -			break; -		case UDESC_STRING: -			if (len == 0) -				break; -			*(u_int8_t *)buf = 0; -			totlen = 1; -			switch (value & 0xff) { -			case 1: /* Vendor */ -				totlen = ohci_str(buf, len, sc->sc_vendor); -				break; -			case 2: /* Product */ -				totlen = ohci_str(buf, len, "OHCI root hub"); -				break; -			} -			break; -		default: -			r = USBD_IOERROR; -			goto ret; -		} -		break; -	case C(UR_GET_INTERFACE, UT_READ_INTERFACE): -		if (len > 0) { -			*(u_int8_t *)buf = 0; -			totlen = 1; -		} -		break; -	case C(UR_GET_STATUS, UT_READ_DEVICE): -		if (len > 1) { -			USETW(((usb_status_t *)buf)->wStatus,UDS_SELF_POWERED); -			totlen = 2; -		} -		break; -	case C(UR_GET_STATUS, UT_READ_INTERFACE): -	case C(UR_GET_STATUS, UT_READ_ENDPOINT): -		if (len > 1) { -			USETW(((usb_status_t *)buf)->wStatus, 0); -			totlen = 2; -		} -		break; -	case C(UR_SET_ADDRESS, UT_WRITE_DEVICE): -		if (value >= USB_MAX_DEVICES) { -			r = USBD_IOERROR; -			goto ret; -		} -		sc->sc_addr = value; -		break; -	case C(UR_SET_CONFIG, UT_WRITE_DEVICE): -		if (value != 0 && value != 1) { -			r = USBD_IOERROR; -			goto ret; -		} -		sc->sc_conf = value; -		break; -	case C(UR_SET_DESCRIPTOR, UT_WRITE_DEVICE): -		break; -	case C(UR_SET_FEATURE, UT_WRITE_DEVICE): -	case C(UR_SET_FEATURE, UT_WRITE_INTERFACE): -	case C(UR_SET_FEATURE, UT_WRITE_ENDPOINT): -		r = USBD_IOERROR; -		goto ret; -	case C(UR_SET_INTERFACE, UT_WRITE_INTERFACE): -		break; -	case C(UR_SYNCH_FRAME, UT_WRITE_ENDPOINT): -		break; -	/* Hub requests */ -	case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_DEVICE): -		break; -	case C(UR_CLEAR_FEATURE, UT_WRITE_CLASS_OTHER): -		DPRINTFN(8, ("ohci_root_ctrl_control: UR_CLEAR_PORT_FEATURE " -			     "port=%d feature=%d\n", -			     index, value)); -		if (index < 1 || index > sc->sc_noport) { -			r = USBD_IOERROR; -			goto ret; -		} -		port = OHCI_RH_PORT_STATUS(index); -		switch(value) { -		case UHF_PORT_ENABLE: -			OWRITE4(sc, port, UPS_CURRENT_CONNECT_STATUS); -			break; -		case UHF_PORT_SUSPEND: -			OWRITE4(sc, port, UPS_OVERCURRENT_INDICATOR); -			break; -		case UHF_PORT_POWER: -			OWRITE4(sc, port, UPS_LOW_SPEED); -			break; -		case UHF_C_PORT_CONNECTION: -			OWRITE4(sc, port, UPS_C_CONNECT_STATUS << 16); -			break; -		case UHF_C_PORT_ENABLE: -			OWRITE4(sc, port, UPS_C_PORT_ENABLED << 16); -			break; -		case UHF_C_PORT_SUSPEND: -			OWRITE4(sc, port, UPS_C_SUSPEND << 16); -			break; -		case UHF_C_PORT_OVER_CURRENT: -			OWRITE4(sc, port, UPS_C_OVERCURRENT_INDICATOR << 16); -			break; -		case UHF_C_PORT_RESET: -			OWRITE4(sc, port, UPS_C_PORT_RESET << 16); -			break; -		default: -			r = USBD_IOERROR; -			goto ret; -		} -		switch(value) { -		case UHF_C_PORT_CONNECTION: -		case UHF_C_PORT_ENABLE: -		case UHF_C_PORT_SUSPEND: -		case UHF_C_PORT_OVER_CURRENT: -		case UHF_C_PORT_RESET: -			/* Enable RHSC interrupt if condition is cleared. */ -			if ((OREAD4(sc, port) >> 16) == 0) -				ohci_rhsc_able(sc, 1); -			break; -		default: -			break; -		} -		break; -	case C(UR_GET_DESCRIPTOR, UT_READ_CLASS_DEVICE): -		if (value != 0) { -			r = USBD_IOERROR; -			goto ret; -		} -		v = OREAD4(sc, OHCI_RH_DESCRIPTOR_A); -		hubd = ohci_hubd; -		hubd.bNbrPorts = sc->sc_noport; -		USETW(hubd.wHubCharacteristics, -		      (v & OHCI_NPS ? UHD_PWR_NO_SWITCH :  -		       v & OHCI_PSM ? UHD_PWR_GANGED : UHD_PWR_INDIVIDUAL) -		      /* XXX overcurrent */ -		      ); -		hubd.bPwrOn2PwrGood = OHCI_GET_POTPGT(v); -		v = OREAD4(sc, OHCI_RH_DESCRIPTOR_B); -		for (i = 0, l = sc->sc_noport; l > 0; i++, l -= 8, v >>= 8)  -			hubd.DeviceRemovable[i++] = (u_int8_t)v; -		hubd.bDescLength = USB_HUB_DESCRIPTOR_SIZE + i; -		l = min(len, hubd.bDescLength); -		totlen = l; -		memcpy(buf, &hubd, l); -		break; -	case C(UR_GET_STATUS, UT_READ_CLASS_DEVICE): -		if (len != 4) { -			r = USBD_IOERROR; -			goto ret; -		} -		memset(buf, 0, len); /* ? XXX */ -		totlen = len; -		break; -	case C(UR_GET_STATUS, UT_READ_CLASS_OTHER): -		DPRINTFN(8,("ohci_root_ctrl_transfer: get port status i=%d\n", -			    index)); -		if (index < 1 || index > sc->sc_noport) { -			r = USBD_IOERROR; -			goto ret; -		} -		if (len != 4) { -			r = USBD_IOERROR; -			goto ret; -		} -		v = OREAD4(sc, OHCI_RH_PORT_STATUS(index)); -		DPRINTFN(8,("ohci_root_ctrl_transfer: port status=0x%04x\n", -			    v)); -		USETW(ps.wPortStatus, v); -		USETW(ps.wPortChange, v >> 16); -		l = min(len, sizeof ps); -		memcpy(buf, &ps, l); -		totlen = l; -		break; -	case C(UR_SET_DESCRIPTOR, UT_WRITE_CLASS_DEVICE): -		r = USBD_IOERROR; -		goto ret; -	case C(UR_SET_FEATURE, UT_WRITE_CLASS_DEVICE): -		break; -	case C(UR_SET_FEATURE, UT_WRITE_CLASS_OTHER): -		if (index < 1 || index > sc->sc_noport) { -			r = USBD_IOERROR; -			goto ret; -		} -		port = OHCI_RH_PORT_STATUS(index); -		switch(value) { -		case UHF_PORT_ENABLE: -			OWRITE4(sc, port, UPS_PORT_ENABLED); -			break; -		case UHF_PORT_SUSPEND: -			OWRITE4(sc, port, UPS_SUSPEND); -			break; -		case UHF_PORT_RESET: -			DPRINTFN(5,("ohci_root_ctrl_transfer: reset port %d\n", -				    index)); -			OWRITE4(sc, port, UPS_RESET); -			for (i = 0; i < 10; i++) { -				usb_delay_ms(&sc->sc_bus, 10); -				if ((OREAD4(sc, port) & UPS_RESET) == 0) -					break; -			} -			DPRINTFN(8,("ohci port %d reset, status = 0x%04x\n", -				    index, OREAD4(sc, port))); -			break; -		case UHF_PORT_POWER: -			DPRINTFN(2,("ohci_root_ctrl_transfer: set port power " -				    "%d\n", index)); -			OWRITE4(sc, port, UPS_PORT_POWER); -			break; -		default: -			r = USBD_IOERROR; -			goto ret; -		} -		break; -	default: -		r = USBD_IOERROR; -		goto ret; -	} -	reqh->actlen = totlen; -	r = USBD_NORMAL_COMPLETION; - ret: -	reqh->status = r; -	reqh->xfercb(reqh); -	usb_start_next(reqh->pipe); -	return (USBD_IN_PROGRESS); -} - -/* Abort a root control request. */ -void -ohci_root_ctrl_abort(reqh) -	usbd_request_handle reqh; -{ -	/* Nothing to do, all transfers are synchronous. */ -} - -/* Close the root pipe. */ -void -ohci_root_ctrl_close(pipe) -	usbd_pipe_handle pipe; -{ -	DPRINTF(("ohci_root_ctrl_close\n")); -} - -usbd_status -ohci_root_intr_transfer(reqh) -	usbd_request_handle reqh; -{ -	int s; -	usbd_status r; - -	s = splusb(); -	r = usb_insert_transfer(reqh); -	splx(s); -	if (r != USBD_NORMAL_COMPLETION) -		return (r); -	else -		return (ohci_root_intr_start(reqh)); -} - -usbd_status -ohci_root_intr_start(reqh) -	usbd_request_handle reqh; -{ -	usbd_pipe_handle pipe = reqh->pipe; -	ohci_softc_t *sc = (ohci_softc_t *)pipe->device->bus; -	struct ohci_pipe *upipe = (struct ohci_pipe *)pipe; -	usb_dma_t *dmap; -	usbd_status r; -	int len; - -	len = reqh->length; -	dmap = &upipe->u.intr.datadma; -	if (len == 0) -		return (USBD_INVAL); /* XXX should it be? */ - -	r = usb_allocmem(sc->sc_dmatag, len, 0, dmap); -	if (r != USBD_NORMAL_COMPLETION) -		return (r); -	sc->sc_intrreqh = reqh; - -	return (USBD_IN_PROGRESS); -} - -/* Abort a root interrupt request. */ -void -ohci_root_intr_abort(reqh) -	usbd_request_handle reqh; -{ -	/* No need to abort. */ -} - -/* Close the root pipe. */ -void -ohci_root_intr_close(pipe) -	usbd_pipe_handle pipe; -{ -	ohci_softc_t *sc = (ohci_softc_t *)pipe->device->bus; -	sc->sc_intrreqh = 0; -	 -	DPRINTF(("ohci_root_intr_close\n")); -} - -/************************/ - -usbd_status -ohci_device_ctrl_transfer(reqh) -	usbd_request_handle reqh; -{ -	int s; -	usbd_status r; - -	s = splusb(); -	r = usb_insert_transfer(reqh); -	splx(s); -	if (r != USBD_NORMAL_COMPLETION) -		return (r); -	else -		return (ohci_device_ctrl_start(reqh)); -} - -usbd_status -ohci_device_ctrl_start(reqh) -	usbd_request_handle reqh; -{ -	ohci_softc_t *sc = (ohci_softc_t *)reqh->pipe->device->bus; -	usbd_status r; - -	if (!reqh->isreq) { -		/* XXX panic */ -		printf("ohci_device_ctrl_transfer: not a request\n"); -		return (USBD_INVAL); -	} - -	r = ohci_device_request(reqh); -	if (r != USBD_NORMAL_COMPLETION) -		return (r); - -	if (sc->sc_bus.use_polling) -		ohci_waitintr(sc, reqh); -	return (USBD_IN_PROGRESS); -} - -/* Abort a device control request. */ -void -ohci_device_ctrl_abort(reqh) -	usbd_request_handle reqh; -{ -	/* XXX inactivate */ -	usb_delay_ms(reqh->pipe->device->bus, 1); /* make sure it is donw */ -	/* XXX call done */ -} - -/* Close a device control pipe. */ -void -ohci_device_ctrl_close(pipe) -	usbd_pipe_handle pipe; -{ -	struct ohci_pipe *opipe = (struct ohci_pipe *)pipe; -	ohci_softc_t *sc = (ohci_softc_t *)pipe->device->bus; -	ohci_soft_ed_t *sed = opipe->sed; -	int s; - -	s = splusb(); -	sed->ed->ed_flags |= LE(OHCI_ED_SKIP); -	if ((LE(sed->ed->ed_tailp) & OHCI_TAILMASK) != LE(sed->ed->ed_headp)) -		usb_delay_ms(&sc->sc_bus, 2); -	ohci_rem_ed(sed, sc->sc_ctrl_head); -	splx(s); -	ohci_free_std(sc, opipe->tail); -	ohci_free_sed(sc, opipe->sed); -	/* XXX free other resources */ -} - -/************************/ - -usbd_status -ohci_device_bulk_transfer(reqh) -	usbd_request_handle reqh; -{ -	int s; -	usbd_status r; - -	s = splusb(); -	r = usb_insert_transfer(reqh); -	splx(s); -	if (r != USBD_NORMAL_COMPLETION) -		return (r); -	else -		return (ohci_device_bulk_start(reqh)); -} - -usbd_status -ohci_device_bulk_start(reqh) -	usbd_request_handle reqh; -{ -	struct ohci_pipe *opipe = (struct ohci_pipe *)reqh->pipe; -	usbd_device_handle dev = opipe->pipe.device; -	ohci_softc_t *sc = (ohci_softc_t *)dev->bus; -	int addr = dev->address; -	ohci_soft_td_t *xfer, *tail; -	ohci_soft_ed_t *sed; -	usb_dma_t *dmap; -	usbd_status r; -	int s, len, isread; - -	if (reqh->isreq) { -		/* XXX panic */ -		printf("ohci_device_bulk_transfer: a request\n"); -		return (USBD_INVAL); -	} - -	len = reqh->length; -	dmap = &opipe->u.bulk.datadma; -	isread = reqh->pipe->endpoint->edesc->bEndpointAddress & UE_IN; -	sed = opipe->sed; - -	opipe->u.bulk.length = len; - -	r = usb_allocmem(sc->sc_dmatag, len, 0, dmap); -	if (r != USBD_NORMAL_COMPLETION) -		goto ret1; - -	tail = ohci_alloc_std(sc); -	if (!tail) { -		r = USBD_NOMEM; -		goto ret2; -	} -	tail->reqh = 0; - -	/* Update device address */ -	sed->ed->ed_flags = LE( -		(LE(sed->ed->ed_flags) & ~OHCI_ED_ADDRMASK) | -		OHCI_ED_SET_FA(addr)); - -	/* Set up data transaction */ -	xfer = opipe->tail; -	xfer->td->td_flags = LE( -		(isread ? OHCI_TD_IN : OHCI_TD_OUT) | OHCI_TD_NOCC | -		OHCI_TD_SET_DI(1) | OHCI_TD_TOGGLE_CARRY | -		(reqh->flags & USBD_SHORT_XFER_OK ? OHCI_TD_R : 0)); -	xfer->td->td_cbp = LE(DMAADDR(dmap)); -	xfer->nexttd = tail; -	xfer->td->td_nexttd = LE(tail->physaddr); -	xfer->td->td_be = LE(LE(xfer->td->td_cbp) + len - 1); -	xfer->len = len; -	xfer->reqh = reqh; - -	reqh->hcpriv = xfer; - -	if (!isread) -		memcpy(KERNADDR(dmap), reqh->buffer, len); - -	/* Insert ED in schedule */ -	s = splusb(); -	ohci_hash_add_td(sc, xfer); -	sed->ed->ed_tailp = LE(tail->physaddr); -	opipe->tail = tail; -	OWRITE4(sc, OHCI_COMMAND_STATUS, OHCI_BLF); -	if (reqh->timeout && !sc->sc_bus.use_polling) { -                usb_timeout(ohci_timeout, reqh, -			    MS_TO_TICKS(reqh->timeout), reqh->timo_handle); -	} -	splx(s); - -	return (USBD_IN_PROGRESS); - - ret2: -	usb_freemem(sc->sc_dmatag, dmap); - ret1: -	return (r); -} - -/* Abort a device bulk request. */ -void -ohci_device_bulk_abort(reqh) -	usbd_request_handle reqh; -{ -#if 0 -	sed->ed->ed_flags |= LE(OHCI_ED_SKIP); -	if ((LE(sed->ed->ed_tailp) & OHCI_TAILMASK) != LE(sed->ed->ed_headp)) -		usb_delay_ms(reqh->pipe->device->bus, 2); -#endif -	/* XXX inactivate */ -	usb_delay_ms(reqh->pipe->device->bus, 1); /* make sure it is done */ -	/* XXX call done */ -} - -/* Close a device bulk pipe. */ -void -ohci_device_bulk_close(pipe) -	usbd_pipe_handle pipe; -{ -	struct ohci_pipe *opipe = (struct ohci_pipe *)pipe; -	usbd_device_handle dev = opipe->pipe.device; -	ohci_softc_t *sc = (ohci_softc_t *)dev->bus; -	int s; - -	s = splusb(); -	ohci_rem_ed(opipe->sed, sc->sc_bulk_head); -	splx(s); -	ohci_free_std(sc, opipe->tail); -	ohci_free_sed(sc, opipe->sed); -	/* XXX free other resources */ -} - -/************************/ - -usbd_status -ohci_device_intr_transfer(reqh) -	usbd_request_handle reqh; -{ -	int s; -	usbd_status r; - -	s = splusb(); -	r = usb_insert_transfer(reqh); -	splx(s); -	if (r != USBD_NORMAL_COMPLETION) -		return (r); -	else -		return (ohci_device_intr_start(reqh)); -} - -usbd_status -ohci_device_intr_start(reqh) -	usbd_request_handle reqh; -{ -	struct ohci_pipe *opipe = (struct ohci_pipe *)reqh->pipe; -	usbd_device_handle dev = opipe->pipe.device; -	ohci_softc_t *sc = (ohci_softc_t *)dev->bus; -	ohci_soft_ed_t *sed = opipe->sed; -	ohci_soft_td_t *xfer, *tail; -	usb_dma_t *dmap; -	usbd_status r; -	int len; -	int s; - -	DPRINTFN(3, ("ohci_device_intr_transfer: reqh=%p buf=%p len=%d " -		     "flags=%d priv=%p\n", -		 reqh, reqh->buffer, reqh->length, reqh->flags, reqh->priv)); - -	if (reqh->isreq) -		panic("ohci_device_intr_transfer: a request\n"); - -	len = reqh->length; -	dmap = &opipe->u.intr.datadma; -	if (len == 0) -		return (USBD_INVAL); /* XXX should it be? */ - -	xfer = opipe->tail; -	tail = ohci_alloc_std(sc); -	if (!tail) { -		r = USBD_NOMEM; -		goto ret1; -	} -	tail->reqh = 0; - -	r = usb_allocmem(sc->sc_dmatag, len, 0, dmap); -	if (r != USBD_NORMAL_COMPLETION) -		goto ret2; - -	xfer->td->td_flags = LE( -		OHCI_TD_IN | OHCI_TD_NOCC |  -		OHCI_TD_SET_DI(1) | OHCI_TD_TOGGLE_CARRY); -	if (reqh->flags & USBD_SHORT_XFER_OK) -		xfer->td->td_flags |= LE(OHCI_TD_R); -	xfer->td->td_cbp = LE(DMAADDR(dmap)); -	xfer->nexttd = tail; -	xfer->td->td_nexttd = LE(tail->physaddr); -	xfer->td->td_be = LE(LE(xfer->td->td_cbp) + len - 1); -	xfer->len = len; -	xfer->reqh = reqh; - -	reqh->hcpriv = xfer; - -#if USB_DEBUG -	if (ohcidebug > 5) { -		printf("ohci_device_intr_transfer:\n"); -		ohci_dump_ed(sed); -		ohci_dump_tds(xfer); -	} -#endif - -	/* Insert ED in schedule */ -	s = splusb(); -	ohci_hash_add_td(sc, xfer); -	sed->ed->ed_tailp = LE(tail->physaddr); -	opipe->tail = tail; -#if 0 -	if (reqh->timeout && !sc->sc_bus.use_polling) { -                usb_timeout(ohci_timeout, reqh, -			    MS_TO_TICKS(reqh->timeout), reqh->timo_handle); -	} -#endif -	sed->ed->ed_flags &= LE(~OHCI_ED_SKIP); - -#ifdef USB_DEBUG -	if (ohcidebug > 5) { -		delay(5000); -		printf("ohci_device_intr_transfer: status=%x\n", -		       OREAD4(sc, OHCI_COMMAND_STATUS)); -		ohci_dump_ed(sed); -		ohci_dump_tds(xfer); -	} -#endif -	/* moved splx(s) because of indefinite printing of TD's */ -	splx(s); - -	return (USBD_IN_PROGRESS); - - ret2: -	ohci_free_std(sc, xfer); - ret1: -	return (r); -} - -/* Abort a device control request. */ -void -ohci_device_intr_abort(reqh) -	usbd_request_handle reqh; -{ -	/* XXX inactivate */ -	usb_delay_ms(reqh->pipe->device->bus, 1); /* make sure it is done */ -	if (reqh->pipe->intrreqh == reqh) { -		DPRINTF(("ohci_device_intr_abort: remove\n")); -		reqh->pipe->intrreqh = 0; -		ohci_intr_done((ohci_softc_t *)reqh->pipe->device->bus, reqh); -	} -} - -/* Close a device interrupt pipe. */ -void -ohci_device_intr_close(pipe) -	usbd_pipe_handle pipe; -{ -	struct ohci_pipe *opipe = (struct ohci_pipe *)pipe; -	ohci_softc_t *sc = (ohci_softc_t *)pipe->device->bus; -	int nslots = opipe->u.intr.nslots; -	int pos = opipe->u.intr.pos; -	int j; -	ohci_soft_ed_t *p, *sed = opipe->sed; -	int s; - -	DPRINTFN(1,("ohci_device_intr_close: pipe=%p nslots=%d pos=%d\n", -		    pipe, nslots, pos)); -	s = splusb(); -	sed->ed->ed_flags |= LE(OHCI_ED_SKIP); -	if ((sed->ed->ed_tailp & LE(OHCI_TAILMASK)) != sed->ed->ed_headp) -		usb_delay_ms(&sc->sc_bus, 2); - -	for (p = sc->sc_eds[pos]; p && p->next != sed; p = p->next) -		; -	if (!p) -		panic("ohci_device_intr_close: ED not found\n"); -	p->next = sed->next; -	p->ed->ed_nexted = sed->ed->ed_nexted; -	splx(s); - -	for (j = 0; j < nslots; j++) -		--sc->sc_bws[pos * nslots + j]; - -	ohci_free_std(sc, opipe->tail); -	ohci_free_sed(sc, opipe->sed); -	/* XXX free other resources */ -} - -usbd_status -ohci_device_setintr(sc, opipe, ival) -	ohci_softc_t *sc; -	struct ohci_pipe *opipe; -	int ival; -{ -	int i, j, s, best; -	u_int npoll, slow, shigh, nslots; -	u_int bestbw, bw; -	ohci_soft_ed_t *hsed, *sed = opipe->sed; - -	DPRINTFN(2, ("ohci_setintr: pipe=%p\n", opipe)); -	if (ival == 0) { -		printf("ohci_setintr: 0 interval\n"); -		return (USBD_INVAL); -	} - -	npoll = OHCI_NO_INTRS; -	while (npoll > ival) -		npoll /= 2; -	DPRINTFN(2, ("ohci_setintr: ival=%d npoll=%d\n", ival, npoll)); - -	/* -	 * We now know which level in the tree the ED must go into. -	 * Figure out which slot has most bandwidth left over. -	 * Slots to examine: -	 * npoll -	 * 1	0 -	 * 2	1 2 -	 * 4	3 4 5 6 -	 * 8	7 8 9 10 11 12 13 14 -	 * N    (N-1) .. (N-1+N-1) -	 */ -	slow = npoll-1; -	shigh = slow + npoll; -	nslots = OHCI_NO_INTRS / npoll; -	for (best = i = slow, bestbw = ~0; i < shigh; i++) { -		bw = 0; -		for (j = 0; j < nslots; j++) -			bw += sc->sc_bws[i * nslots + j]; -		if (bw < bestbw) { -			best = i; -			bestbw = bw; -		} -	} -	DPRINTFN(2, ("ohci_setintr: best=%d(%d..%d) bestbw=%d\n",  -		     best, slow, shigh, bestbw)); - -	s = splusb(); -	hsed = sc->sc_eds[best]; -	sed->next = hsed->next; -	sed->ed->ed_nexted = hsed->ed->ed_nexted; -	hsed->next = sed; -	hsed->ed->ed_nexted = LE(sed->physaddr); -	splx(s); - -	for (j = 0; j < nslots; j++) -		++sc->sc_bws[best * nslots + j]; -	opipe->u.intr.nslots = nslots; -	opipe->u.intr.pos = best; - -	DPRINTFN(5, ("ohci_setintr: returns %p\n", opipe)); -	return (USBD_NORMAL_COMPLETION); -} - | 
