uhci.c
来自「基于组件方式开发操作系统的OSKIT源代码」· C语言 代码 · 共 2,637 行 · 第 1/5 页
C
2,637 行
/* $NetBSD: uhci.c,v 1.24 1999/02/20 23:26:16 augustss Exp $ *//* $FreeBSD: src/sys/dev/usb/uhci.c,v 1.7.2.2 1999/05/08 23:04:46 n_hibma Exp $ *//* * 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 Universal Host Controller driver. * Handles PIIX3 and PIIX4. * * Data sheets: ftp://download.intel.com/design/intarch/datashts/29055002.pdf * ftp://download.intel.com/design/intarch/datashts/29056201.pdf * UHCI spec: http://www.intel.com/design/usb/uhci11d.pdf * USB spec: http://www.usb.org/cgi-usb/mailmerge.cgi/home/usb/docs/developers/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 <dev/usb/usb.h>#include <dev/usb/usbdi.h>#include <dev/usb/usbdivar.h>#include <dev/usb/usb_mem.h>#include <dev/usb/usb_quirks.h>#include <dev/usb/uhcireg.h>#include <dev/usb/uhcivar.h>#if defined(__FreeBSD__)#include <machine/clock.h>#define delay(d) DELAY(d)#endif#ifdef UHCI_DEBUG#define DPRINTF(x) if (uhcidebug) logprintf x#define DPRINTFN(n,x) if (uhcidebug>(n)) logprintf xint uhcidebug = 1;#else#define DPRINTF(x)#define DPRINTFN(n,x)#endif#define MS_TO_TICKS(ms) ((ms) * hz / 1000)struct uhci_pipe { struct usbd_pipe pipe; uhci_intr_info_t *iinfo; int newtoggle; /* Info needed for different pipe kinds. */ union { /* Control pipe */ struct { uhci_soft_qh_t *sqh; usb_dma_t reqdma; usb_dma_t datadma; uhci_soft_td_t *setup, *stat; u_int length; } ctl; /* Interrupt pipe */ struct { usb_dma_t datadma; int npoll; uhci_soft_qh_t **qhs; } intr; /* Bulk pipe */ struct { uhci_soft_qh_t *sqh; usb_dma_t datadma; u_int length; int isread; } bulk; /* Iso pipe */ struct iso { u_int bufsize; u_int nbuf; usb_dma_t *bufs; uhci_soft_td_t **stds; } iso; } u;};/* * The uhci_intr_info free list can be global since they contain * no dma specific data. The other free lists do. */LIST_HEAD(, uhci_intr_info) uhci_ii_free;void uhci_busreset __P((uhci_softc_t *));usbd_status uhci_run __P((uhci_softc_t *, int run));uhci_soft_td_t *uhci_alloc_std __P((uhci_softc_t *));void uhci_free_std __P((uhci_softc_t *, uhci_soft_td_t *));uhci_soft_qh_t *uhci_alloc_sqh __P((uhci_softc_t *));void uhci_free_sqh __P((uhci_softc_t *, uhci_soft_qh_t *));uhci_intr_info_t *uhci_alloc_intr_info __P((uhci_softc_t *));void uhci_free_intr_info __P((uhci_intr_info_t *ii));#if 0void uhci_enter_ctl_q __P((uhci_softc_t *, uhci_soft_qh_t *, uhci_intr_info_t *));void uhci_exit_ctl_q __P((uhci_softc_t *, uhci_soft_qh_t *));#endifvoid uhci_free_std_chain __P((uhci_softc_t *, uhci_soft_td_t *, uhci_soft_td_t *));usbd_status uhci_alloc_std_chain __P((struct uhci_pipe *, uhci_softc_t *, int, int, int, usb_dma_t *, uhci_soft_td_t **, uhci_soft_td_t **));void uhci_timo __P((void *));void uhci_waitintr __P((uhci_softc_t *, usbd_request_handle));void uhci_check_intr __P((uhci_softc_t *, uhci_intr_info_t *));void uhci_ii_done __P((uhci_intr_info_t *, int));void uhci_timeout __P((void *));void uhci_wakeup_ctrl __P((void *, int, int, void *, int));void uhci_lock_frames __P((uhci_softc_t *));void uhci_unlock_frames __P((uhci_softc_t *));void uhci_add_ctrl __P((uhci_softc_t *, uhci_soft_qh_t *));void uhci_add_bulk __P((uhci_softc_t *, uhci_soft_qh_t *));void uhci_remove_ctrl __P((uhci_softc_t *, uhci_soft_qh_t *));void uhci_remove_bulk __P((uhci_softc_t *, uhci_soft_qh_t *));int uhci_str __P((usb_string_descriptor_t *, int, char *));void uhci_wakeup_cb __P((usbd_request_handle reqh));usbd_status uhci_device_ctrl_transfer __P((usbd_request_handle));usbd_status uhci_device_ctrl_start __P((usbd_request_handle));void uhci_device_ctrl_abort __P((usbd_request_handle));void uhci_device_ctrl_close __P((usbd_pipe_handle));usbd_status uhci_device_intr_transfer __P((usbd_request_handle));usbd_status uhci_device_intr_start __P((usbd_request_handle));void uhci_device_intr_abort __P((usbd_request_handle));void uhci_device_intr_close __P((usbd_pipe_handle));usbd_status uhci_device_bulk_transfer __P((usbd_request_handle));usbd_status uhci_device_bulk_start __P((usbd_request_handle));void uhci_device_bulk_abort __P((usbd_request_handle));void uhci_device_bulk_close __P((usbd_pipe_handle));usbd_status uhci_device_isoc_transfer __P((usbd_request_handle));usbd_status uhci_device_isoc_start __P((usbd_request_handle));void uhci_device_isoc_abort __P((usbd_request_handle));void uhci_device_isoc_close __P((usbd_pipe_handle));usbd_status uhci_device_isoc_setbuf __P((usbd_pipe_handle, u_int, u_int));usbd_status uhci_root_ctrl_transfer __P((usbd_request_handle));usbd_status uhci_root_ctrl_start __P((usbd_request_handle));void uhci_root_ctrl_abort __P((usbd_request_handle));void uhci_root_ctrl_close __P((usbd_pipe_handle));usbd_status uhci_root_intr_transfer __P((usbd_request_handle));usbd_status uhci_root_intr_start __P((usbd_request_handle));void uhci_root_intr_abort __P((usbd_request_handle));void uhci_root_intr_close __P((usbd_pipe_handle));usbd_status uhci_open __P((usbd_pipe_handle));void uhci_poll __P((struct usbd_bus *));usbd_status uhci_device_request __P((usbd_request_handle reqh));void uhci_ctrl_done __P((uhci_intr_info_t *ii));void uhci_bulk_done __P((uhci_intr_info_t *ii));void uhci_add_intr __P((uhci_softc_t *, int, uhci_soft_qh_t *));void uhci_remove_intr __P((uhci_softc_t *, int, uhci_soft_qh_t *));usbd_status uhci_device_setintr __P((uhci_softc_t *sc, struct uhci_pipe *pipe, int ival));void uhci_intr_done __P((uhci_intr_info_t *ii));void uhci_isoc_done __P((uhci_intr_info_t *ii));#ifdef UHCI_DEBUGstatic void uhci_dumpregs __P((uhci_softc_t *));void uhci_dump_tds __P((uhci_soft_td_t *));void uhci_dump_qh __P((uhci_soft_qh_t *));void uhci_dump __P((void));void uhci_dump_td __P((uhci_soft_td_t *));#endif#if defined(__NetBSD__)#define UWRITE2(sc, r, x) bus_space_write_2((sc)->iot, (sc)->ioh, (r), (x))#define UWRITE4(sc, r, x) bus_space_write_4((sc)->iot, (sc)->ioh, (r), (x))#define UREAD2(sc, r) bus_space_read_2((sc)->iot, (sc)->ioh, (r))#define UREAD4(sc, r) bus_space_read_4((sc)->iot, (sc)->ioh, (r))#elif defined(__FreeBSD__)#define UWRITE2(sc,r,x) outw((sc)->sc_iobase + (r), (x))#define UWRITE4(sc,r,x) outl((sc)->sc_iobase + (r), (x))#define UREAD2(sc,r) inw((sc)->sc_iobase + (r))#define UREAD4(sc,r) inl((sc)->sc_iobase + (r))#endif#define UHCICMD(sc, cmd) UWRITE2(sc, UHCI_CMD, cmd)#define UHCISTS(sc) UREAD2(sc, UHCI_STS)#define UHCI_RESET_TIMEOUT 100 /* reset timeout */#define UHCI_CURFRAME(sc) (UREAD2(sc, UHCI_FRNUM) & UHCI_FRNUM_MASK)#define UHCI_INTR_ENDPT 1struct usbd_methods uhci_root_ctrl_methods = { uhci_root_ctrl_transfer, uhci_root_ctrl_start, uhci_root_ctrl_abort, uhci_root_ctrl_close, 0,};struct usbd_methods uhci_root_intr_methods = { uhci_root_intr_transfer, uhci_root_intr_start, uhci_root_intr_abort, uhci_root_intr_close, 0,};struct usbd_methods uhci_device_ctrl_methods = { uhci_device_ctrl_transfer, uhci_device_ctrl_start, uhci_device_ctrl_abort, uhci_device_ctrl_close, 0,};struct usbd_methods uhci_device_intr_methods = { uhci_device_intr_transfer, uhci_device_intr_start, uhci_device_intr_abort, uhci_device_intr_close, 0,};struct usbd_methods uhci_device_bulk_methods = { uhci_device_bulk_transfer, uhci_device_bulk_start, uhci_device_bulk_abort, uhci_device_bulk_close, 0,};struct usbd_methods uhci_device_isoc_methods = { uhci_device_isoc_transfer, uhci_device_isoc_start, uhci_device_isoc_abort, uhci_device_isoc_close, uhci_device_isoc_setbuf,};voiduhci_busreset(sc) uhci_softc_t *sc;{ UHCICMD(sc, UHCI_CMD_GRESET); /* global reset */ usb_delay_ms(&sc->sc_bus, USB_BUS_RESET_DELAY); /* wait a little */ UHCICMD(sc, 0); /* do nothing */}usbd_statusuhci_init(sc) uhci_softc_t *sc;{ usbd_status r; int i, j; uhci_soft_qh_t *csqh, *bsqh, *sqh; uhci_soft_td_t *std; usb_dma_t dma; static int uhci_global_init_done = 0; DPRINTFN(1,("uhci_init: start\n")); if (!uhci_global_init_done) { uhci_global_init_done = 1; LIST_INIT(&uhci_ii_free); } uhci_run(sc, 0); /* stop the controller */ UWRITE2(sc, UHCI_INTR, 0); /* disable interrupts */ uhci_busreset(sc); /* Allocate and initialize real frame array. */ r = usb_allocmem(sc->sc_dmatag, UHCI_FRAMELIST_COUNT * sizeof(uhci_physaddr_t), UHCI_FRAMELIST_ALIGN, &dma); if (r != USBD_NORMAL_COMPLETION) return (r); sc->sc_pframes = KERNADDR(&dma); UWRITE2(sc, UHCI_FRNUM, 0); /* set frame number to 0 */ UWRITE4(sc, UHCI_FLBASEADDR, DMAADDR(&dma)); /* set frame list */ /* Allocate the dummy QH where bulk traffic will be queued. */ bsqh = uhci_alloc_sqh(sc); if (!bsqh) return (USBD_NOMEM); bsqh->qh->qh_hlink = UHCI_PTR_T; /* end of QH chain */ bsqh->qh->qh_elink = UHCI_PTR_T; sc->sc_bulk_start = sc->sc_bulk_end = bsqh; /* Allocate the dummy QH where control traffic will be queued. */ csqh = uhci_alloc_sqh(sc); if (!csqh) return (USBD_NOMEM); csqh->qh->hlink = bsqh; csqh->qh->qh_hlink = bsqh->physaddr | UHCI_PTR_Q; csqh->qh->qh_elink = UHCI_PTR_T; sc->sc_ctl_start = sc->sc_ctl_end = csqh; /* * Make all (virtual) frame list pointers point to the interrupt * queue heads and the interrupt queue heads at the control * queue head and point the physical frame list to the virtual. */ for(i = 0; i < UHCI_VFRAMELIST_COUNT; i++) { std = uhci_alloc_std(sc); sqh = uhci_alloc_sqh(sc); if (!std || !sqh) return (USBD_NOMEM); std->td->link.sqh = sqh; std->td->td_link = sqh->physaddr | UHCI_PTR_Q; std->td->td_status = UHCI_TD_IOS; /* iso, inactive */ std->td->td_token = 0; std->td->td_buffer = 0; sqh->qh->hlink = csqh; sqh->qh->qh_hlink = csqh->physaddr | UHCI_PTR_Q; sqh->qh->elink = 0; sqh->qh->qh_elink = UHCI_PTR_T; sc->sc_vframes[i].htd = std; sc->sc_vframes[i].etd = std; sc->sc_vframes[i].hqh = sqh; sc->sc_vframes[i].eqh = sqh; for (j = i; j < UHCI_FRAMELIST_COUNT; j += UHCI_VFRAMELIST_COUNT) sc->sc_pframes[j] = std->physaddr; } LIST_INIT(&sc->sc_intrhead); /* Set up the bus struct. */ sc->sc_bus.open_pipe = uhci_open; sc->sc_bus.pipe_size = sizeof(struct uhci_pipe); sc->sc_bus.do_poll = uhci_poll; DPRINTFN(1,("uhci_init: enabling\n")); UWRITE2(sc, UHCI_INTR, UHCI_INTR_TOCRCIE | UHCI_INTR_RIE | UHCI_INTR_IOCE | UHCI_INTR_SPIE); /* enable interrupts */ return (uhci_run(sc, 1)); /* and here we go... */}#ifdef UHCI_DEBUGstatic voiduhci_dumpregs(sc) uhci_softc_t *sc;{ printf("%s: regs: cmd=%04x, sts=%04x, intr=%04x, frnum=%04x, " "flbase=%08x, sof=%02x, portsc1=%04x, portsc2=%04x, ", USBDEVNAME(sc->sc_bus.bdev), UREAD2(sc, UHCI_CMD), UREAD2(sc, UHCI_STS), UREAD2(sc, UHCI_INTR), UREAD2(sc, UHCI_FRNUM), UREAD4(sc, UHCI_FLBASEADDR), UREAD1(sc, UHCI_SOF), UREAD2(sc, UHCI_PORTSC1), UREAD2(sc, UHCI_PORTSC2));}int uhci_longtd = 1;voiduhci_dump_td(p) uhci_soft_td_t *p;{ printf("TD(%p) at %08lx link=0x%08lx st=0x%08lx tok=0x%08lx buf=0x%08lx\n", p, (long)p->physaddr, (long)p->td->td_link, (long)p->td->td_status, (long)p->td->td_token, (long)p->td->td_buffer); if (uhci_longtd) printf(" %b %b,errcnt=%d,actlen=%d pid=%02x,addr=%d,endpt=%d," "D=%d,maxlen=%d\n", (int)p->td->td_link, "\20\1T\2Q\3VF", (int)p->td->td_status, "\20\22BITSTUFF\23CRCTO\24NAK\25BABBLE\26DBUFFER\27" "STALLED\30ACTIVE\31IOC\32ISO\33LS\36SPD", UHCI_TD_GET_ERRCNT(p->td->td_status), UHCI_TD_GET_ACTLEN(p->td->td_status), UHCI_TD_GET_PID(p->td->td_token), UHCI_TD_GET_DEVADDR(p->td->td_token), UHCI_TD_GET_ENDPT(p->td->td_token), UHCI_TD_GET_DT(p->td->td_token), UHCI_TD_GET_MAXLEN(p->td->td_token));}voiduhci_dump_qh(p) uhci_soft_qh_t *p;{ printf("QH(%p) at %08x: hlink=%08x elink=%08x\n", p, (int)p->physaddr, p->qh->qh_hlink, p->qh->qh_elink);}#if 0voiduhci_dump(){ uhci_softc_t *sc = uhci; uhci_dumpregs(sc); printf("intrs=%d\n", sc->sc_intrs); printf("framelist[i].link = %08x\n", sc->sc_framelist[0].link); uhci_dump_qh(sc->sc_ctl_start->qh->hlink);}#endifvoiduhci_dump_tds(std) uhci_soft_td_t *std;{ uhci_soft_td_t *p; for(p = std; p; p = p->td->link.std) uhci_dump_td(p);}#endif/* * This routine is executed periodically and simulates interrupts * from the root controller interrupt pipe for port status change. */voiduhci_timo(addr) void *addr;{ usbd_request_handle reqh = addr; usbd_pipe_handle pipe = reqh->pipe; uhci_softc_t *sc = (uhci_softc_t *)pipe->device->bus; struct uhci_pipe *upipe = (struct uhci_pipe *)pipe; int s; u_char *p; DPRINTFN(15, ("uhci_timo\n")); p = KERNADDR(&upipe->u.intr.datadma); p[0] = 0; if (UREAD2(sc, UHCI_PORTSC1) & (UHCI_PORTSC_CSC|UHCI_PORTSC_OCIC)) p[0] |= 1<<1; if (UREAD2(sc, UHCI_PORTSC2) & (UHCI_PORTSC_CSC|UHCI_PORTSC_OCIC)) p[0] |= 1<<2; s = splusb(); if (p[0] != 0) { reqh->actlen = 1; reqh->status = USBD_NORMAL_COMPLETION; reqh->xfercb(reqh); } if (reqh->pipe->intrreqh == reqh) { usb_timeout(uhci_timo, reqh, sc->sc_ival, reqh->timo_handle); } else { usb_freemem(sc->sc_dmatag, &upipe->u.intr.datadma); usb_start_next(reqh->pipe); } splx(s);}voiduhci_lock_frames(sc) uhci_softc_t *sc;{ int s = splusb(); while (sc->sc_vflock) { sc->sc_vflock |= UHCI_WANT_LOCK; tsleep(&sc->sc_vflock, PRIBIO, "uhcqhl", 0); } sc->sc_vflock = UHCI_HAS_LOCK; splx(s);}voiduhci_unlock_frames(sc) uhci_softc_t *sc;{
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?