12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163 |
- /* $OpenBSD: pxa27x_udc.c,v 1.31 2015/05/15 13:32:08 jsg Exp $ */
- /*
- * Copyright (c) 2007 Dale Rahn <drahn@openbsd.org>
- * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
- * Copyright (c) 2005 David Gwynne <dlg@openbsd.org>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
- #include <sys/param.h>
- #include <sys/systm.h>
- #include <sys/device.h>
- #include <sys/kernel.h>
- #include <sys/malloc.h>
- #include <sys/timeout.h>
- #include <machine/intr.h>
- #include <machine/bus.h>
- #include <dev/usb/usb.h>
- #include <dev/usb/usbdi.h>
- #include <dev/usb/usbdivar.h>
- #include <dev/usb/usbf.h>
- #include <dev/usb/usbfvar.h>
- #include <arm/xscale/pxa2x0reg.h>
- #include <arm/xscale/pxa2x0var.h>
- #include <arm/xscale/pxa2x0_gpio.h>
- #include <arm/xscale/pxa27x_udc.h>
- #include "usbf.h"
- struct pxaudc_xfer {
- struct usbf_xfer xfer;
- u_int16_t frmlen;
- };
- struct pxaudc_pipe {
- struct usbf_pipe pipe;
- // LIST_ENTRY(pxaudc_pipe) list;
- };
- void pxaudc_enable(struct pxaudc_softc *);
- void pxaudc_disable(struct pxaudc_softc *);
- void pxaudc_read_ep0(struct pxaudc_softc *, struct usbf_xfer *);
- void pxaudc_read_epN(struct pxaudc_softc *sc, int ep);
- void pxaudc_write_ep0(struct pxaudc_softc *, struct usbf_xfer *);
- void pxaudc_write(struct pxaudc_softc *, struct usbf_xfer *);
- void pxaudc_write_epN(struct pxaudc_softc *sc, int ep);
- int pxaudc_connect_intr(void *);
- int pxaudc_intr(void *);
- void pxaudc_intr1(struct pxaudc_softc *);
- void pxaudc_ep0_intr(struct pxaudc_softc *);
- void pxaudc_epN_intr(struct pxaudc_softc *sc, int ep, int isr);
- usbf_status pxaudc_open(struct usbf_pipe *);
- void pxaudc_softintr(void *);
- usbf_status pxaudc_allocm(struct usbf_bus *, struct usb_dma *, u_int32_t);
- void pxaudc_freem(struct usbf_bus *, struct usb_dma *);
- struct usbf_xfer *pxaudc_allocx(struct usbf_bus *);
- void pxaudc_freex(struct usbf_bus *, struct usbf_xfer *);
- usbf_status pxaudc_ctrl_transfer(struct usbf_xfer *);
- usbf_status pxaudc_ctrl_start(struct usbf_xfer *);
- void pxaudc_ctrl_abort(struct usbf_xfer *);
- void pxaudc_ctrl_done(struct usbf_xfer *);
- void pxaudc_ctrl_close(struct usbf_pipe *);
- usbf_status pxaudc_bulk_transfer(struct usbf_xfer *);
- usbf_status pxaudc_bulk_start(struct usbf_xfer *);
- void pxaudc_bulk_abort(struct usbf_xfer *);
- void pxaudc_bulk_done(struct usbf_xfer *);
- void pxaudc_bulk_close(struct usbf_pipe *);
- struct cfdriver pxaudc_cd = {
- NULL, "pxaudc", DV_DULL
- };
- #if NUSBF > 0
- struct usbf_bus_methods pxaudc_bus_methods = {
- pxaudc_open,
- pxaudc_softintr,
- pxaudc_allocm,
- pxaudc_freem,
- pxaudc_allocx,
- pxaudc_freex
- };
- struct usbf_pipe_methods pxaudc_ctrl_methods = {
- pxaudc_ctrl_transfer,
- pxaudc_ctrl_start,
- pxaudc_ctrl_abort,
- pxaudc_ctrl_done,
- pxaudc_ctrl_close
- };
- struct usbf_pipe_methods pxaudc_bulk_methods = {
- pxaudc_bulk_transfer,
- pxaudc_bulk_start,
- pxaudc_bulk_abort,
- pxaudc_bulk_done,
- pxaudc_bulk_close
- };
- #endif /* NUSBF > 0 */
- #define DEVNAME(sc) ((sc)->sc_bus.bdev.dv_xname)
- #define CSR_READ_4(sc, reg) \
- bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))
- #define CSR_WRITE_4(sc, reg, val) \
- bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
- #define CSR_WRITE_1(sc, reg, val) \
- bus_space_write_1((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
- #define CSR_SET_4(sc, reg, val) \
- CSR_WRITE_4((sc), (reg), CSR_READ_4((sc), (reg)) | (val))
- #define CSR_CLR_4(sc, reg, val) \
- CSR_WRITE_4((sc), (reg), CSR_READ_4((sc), (reg)) & ~(val))
- #ifndef PXAUDC_DEBUG
- #define DPRINTF(l, x) do {} while (0)
- #else
- int pxaudcdebug = 0;
- #define DPRINTF(l, x) if ((l) <= pxaudcdebug) printf x; else {}
- #endif
- int
- pxaudc_match(void)
- {
- if ((cputype & ~CPU_ID_XSCALE_COREREV_MASK) != CPU_ID_PXA27X)
- return (0);
- return (1);
- }
- void
- pxaudc_attach(struct pxaudc_softc *sc, void *aux)
- {
- struct pxaip_attach_args *pxa = aux;
- #if NUSBF > 0
- int i;
- #endif
- sc->sc_iot = pxa->pxa_iot;
- if (bus_space_map(sc->sc_iot, PXA2X0_USBDC_BASE, PXA2X0_USBDC_SIZE, 0,
- &sc->sc_ioh)) {
- printf(": cannot map mem space\n");
- return;
- }
- sc->sc_size = PXA2X0_USBDC_SIZE;
- printf(": USB Device Controller\n");
- bus_space_barrier(sc->sc_iot, sc->sc_ioh, 0, sc->sc_size,
- BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE);
- /* Set up GPIO pins and disable the controller. */
- pxaudc_disable(sc);
- #if NUSBF > 0
- /* Establish USB device interrupt. */
- sc->sc_ih = pxa2x0_intr_establish(PXA2X0_INT_USB, IPL_USB,
- pxaudc_intr, sc, DEVNAME(sc));
- if (sc->sc_ih == NULL) {
- printf(": unable to establish interrupt\n");
- bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_size);
- sc->sc_size = 0;
- return;
- }
- /* Establish device connect interrupt. */
- #if 0
- sc->sc_conn_ih = pxa2x0_gpio_intr_establish(PXA_USB_DEVICE_PIN, /* XXX */
- IST_EDGE_BOTH, IPL_USB, pxaudc_connect_intr, sc, "usbc");
- #endif
- sc->sc_conn_ih = pxa2x0_gpio_intr_establish(sc->sc_gpio_detect,
- IST_EDGE_BOTH, IPL_USB, pxaudc_connect_intr, sc, "usbc");
- if (sc->sc_conn_ih == NULL) {
- printf(": unable to establish connect interrupt\n");
- pxa2x0_intr_disestablish(sc->sc_ih);
- bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_size);
- sc->sc_ioh = 0;
- sc->sc_size = 0;
- return;
- }
- /* Set up the bus struct. */
- sc->sc_bus.methods = &pxaudc_bus_methods;
- sc->sc_bus.pipe_size = sizeof(struct pxaudc_pipe);
- sc->sc_bus.ep0_maxp = PXAUDC_EP0MAXP;
- sc->sc_bus.usbrev = USBREV_1_1;
- sc->sc_bus.dmatag = pxa->pxa_dmat;
- sc->sc_npipe = 0; /* ep0 is always there. */
- sc->sc_ep_map[0] = 0;
- /* 16 == max logical endpoints */
- for (i = 1; i < 16; i++) {
- sc->sc_ep_map[i] = -1;
- }
- /* Attach logical device and function. */
- (void)config_found((struct device *)sc, &sc->sc_bus, NULL);
- /* Enable the controller unless we're now acting as a host. */
- if (!sc->sc_is_host())
- pxaudc_enable(sc);
- #endif
- }
- int
- pxaudc_detach(struct pxaudc_softc *sc, int flags)
- {
- if (sc->sc_conn_ih != NULL)
- pxa2x0_gpio_intr_disestablish(sc->sc_conn_ih);
- if (sc->sc_ih != NULL)
- pxa2x0_intr_disestablish(sc->sc_ih);
- if (sc->sc_size) {
- bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_size);
- sc->sc_size = 0;
- }
- return (0);
- }
- int
- pxaudc_activate(struct pxaudc_softc *self, int act)
- {
- struct pxaudc_softc *sc = (struct pxaudc_softc *)self;
- switch (act) {
- case DVACT_SUSPEND:
- pxaudc_disable(sc);
- break;
- case DVACT_RESUME:
- pxaudc_enable(sc);
- break;
- }
- return 0;
- }
- /*
- * Register manipulation
- */
- #if 0
- static void
- pxaudc_dump_regs(struct pxaudc_softc *sc)
- {
- printf("UDCCR\t%b\n", CSR_READ_4(sc, USBDC_UDCCR),
- USBDC_UDCCR_BITS);
- printf("UDCICR0\t%b\n", CSR_READ_4(sc, USBDC_UDCICR0),
- USBDC_UDCISR0_BITS);
- printf("UDCICR1\t%b\n", CSR_READ_4(sc, USBDC_UDCICR1),
- USBDC_UDCISR1_BITS);
- printf("OTGICR\t%b\n", CSR_READ_4(sc, USBDC_UDCOTGICR),
- USBDC_UDCOTGISR_BITS);
- }
- #endif
- void
- pxaudc_enable(struct pxaudc_softc *sc)
- {
- int i;
- DPRINTF(10,("pxaudc_enable\n"));
- /* Start the clocks. */
- pxa2x0_clkman_config(CKEN_USBDC, 1);
- #if 0
- /* Configure Port 2 for USB device. */
- CSR_WRITE_4(sc, USBDC_UP2OCR, USBDC_UP2OCR_DMPUE |
- USBDC_UP2OCR_DPPUE | USBDC_UP2OCR_HXOE);
- #else
- /* Configure Port 2 for USB device. */
- CSR_WRITE_4(sc, USBDC_UP2OCR, USBDC_UP2OCR_DPPUE | USBDC_UP2OCR_HXOE);
- #endif
- CSR_SET_4(sc, USBDC_UDCCR, 0);
- sc->sc_icr0 = 0;
- sc->sc_icr1 = 0;
- for (i = 1; i < PXAUDC_NEP; i++)
- CSR_WRITE_4(sc, USBDC_UDCECR(i), 0); /* disable endpoints */
- for (i = 1; i < sc->sc_npipe; i++) {
- if (sc->sc_pipe[i] != NULL) {
- struct usbf_endpoint *ep =
- sc->sc_pipe[i]->pipe.endpoint;
- u_int32_t cr;
- int dir = usbf_endpoint_dir(ep);
- usb_endpoint_descriptor_t *ed = ep->edesc;
- if (i < 16)
- sc->sc_icr0 |= USBDC_UDCICR0_IE(i);
- else
- sc->sc_icr1 |= USBDC_UDCICR1_IE(i-16);
- cr = USBDC_UDCECR_EE | USBDC_UDCECR_DE;
- cr |= USBDC_UDCECR_ENs(
- UE_GET_ADDR(ed->bEndpointAddress));
- cr |= USBDC_UDCECR_MPSs(UGETW(ed->wMaxPacketSize));
- cr |= USBDC_UDCECR_ETs(ed->bmAttributes & UE_XFERTYPE);
- if (dir == UE_DIR_IN)
- cr |= USBDC_UDCECR_ED;
- /* XXX - until pipe has cn/in/ain */
- cr |= USBDC_UDCECR_AISNs(0) | USBDC_UDCECR_INs(0) |
- USBDC_UDCECR_CNs(1);
- CSR_WRITE_4(sc, USBDC_UDCECR(i), cr);
- /* clear old status */
- CSR_WRITE_4(sc, USBDC_UDCCSR(1),
- USBDC_UDCCSR_PC | USBDC_UDCCSR_TRN |
- USBDC_UDCCSR_SST | USBDC_UDCCSR_FEF);
- }
- }
- CSR_WRITE_4(sc, USBDC_UDCISR0, 0xffffffff); /* clear all */
- CSR_WRITE_4(sc, USBDC_UDCISR1, 0xffffffff); /* clear all */
- CSR_SET_4(sc, USBDC_UDCCSR0, USBDC_UDCCSR0_ACM);
- /* Enable interrupts for configured endpoints. */
- CSR_WRITE_4(sc, USBDC_UDCICR0, USBDC_UDCICR0_IE(0) |
- sc->sc_icr0);
- CSR_WRITE_4(sc, USBDC_UDCICR1, USBDC_UDCICR1_IERS |
- USBDC_UDCICR1_IESU | USBDC_UDCICR1_IERU |
- USBDC_UDCICR1_IECC | sc->sc_icr1);
- /* Enable the controller. */
- CSR_CLR_4(sc, USBDC_UDCCR, USBDC_UDCCR_EMCE);
- CSR_SET_4(sc, USBDC_UDCCR, USBDC_UDCCR_UDE);
- /* Enable USB client on port 2. */
- pxa2x0_gpio_clear_bit(37); /* USB_P2_8 */
- }
- void
- pxaudc_disable(struct pxaudc_softc *sc)
- {
- DPRINTF(10,("pxaudc_disable\n"));
- /* Disable the controller. */
- CSR_CLR_4(sc, USBDC_UDCCR, USBDC_UDCCR_UDE);
- /* Disable all interrupts. */
- CSR_WRITE_4(sc, USBDC_UDCICR0, 0);
- CSR_WRITE_4(sc, USBDC_UDCICR1, 0);
- CSR_WRITE_4(sc, USBDC_UDCOTGICR, 0);
- /* Set Port 2 output to "Non-OTG Host with Differential Port". */
- CSR_WRITE_4(sc, USBDC_UP2OCR, USBDC_UP2OCR_HXS | USBDC_UP2OCR_HXOE);
- /* Set "Host Port 2 Transceiver D Pull Down Enable". */
- CSR_SET_4(sc, USBDC_UP2OCR, USBDC_UP2OCR_DMPDE);
- /* Stop the clocks. */
- pxa2x0_clkman_config(CKEN_USBDC, 0);
- /* Enable USB host on port 2. */
- pxa2x0_gpio_set_bit(37); /* USB_P2_8 */
- }
- #if NUSBF > 0
- /*
- * Endpoint FIFO handling
- */
- void
- pxaudc_read_ep0(struct pxaudc_softc *sc, struct usbf_xfer *xfer)
- {
- size_t len;
- u_int8_t *p;
- xfer->actlen = CSR_READ_4(sc, USBDC_UDCBCR(0));
- len = MIN(xfer->actlen, xfer->length);
- p = xfer->buffer;
- while (CSR_READ_4(sc, USBDC_UDCCSR0) & USBDC_UDCCSR0_RNE) {
- u_int32_t v = CSR_READ_4(sc, USBDC_UDCDR(0));
- if (len > 0) {
- if (((unsigned)p & 0x3) == 0)
- *(u_int32_t *)p = v;
- else {
- *(p+0) = v & 0xff;
- *(p+1) = (v >> 8) & 0xff;
- *(p+2) = (v >> 16) & 0xff;
- *(p+3) = (v >> 24) & 0xff;
- }
- p += 4;
- len -= 4;
- }
- }
- CSR_WRITE_4(sc, USBDC_UDCCSR0, USBDC_UDCCSR0_SA | USBDC_UDCCSR0_OPC);
- xfer->status = USBF_NORMAL_COMPLETION;
- usbf_transfer_complete(xfer);
- }
- void
- pxaudc_read_epN(struct pxaudc_softc *sc, int ep)
- {
- size_t len, tlen;
- u_int8_t *p;
- struct pxaudc_pipe *ppipe;
- struct usbf_pipe *pipe = NULL;
- struct usbf_xfer *xfer = NULL;
- int count;
- u_int32_t csr;
- ppipe = sc->sc_pipe[ep];
- if (ppipe == NULL) {
- return;
- }
- pipe = &ppipe->pipe;
- again:
- xfer = SIMPLEQ_FIRST(&pipe->queue);
- if (xfer == NULL) {
- printf("pxaudc_read_epN: ep %d, no xfer\n", ep);
- return;
- }
- count = CSR_READ_4(sc, USBDC_UDCBCR(ep));
- tlen = len = MIN(count, xfer->length - xfer->actlen);
- p = xfer->buffer + xfer->actlen;
- csr = CSR_READ_4(sc, USBDC_UDCCSR(ep));
- if ((csr & USBDC_UDCCSR_PC) && count == 0)
- {
- #ifdef DEBUG_RX
- printf("trans1 complete\n");
- #endif
- xfer->status = USBF_NORMAL_COMPLETION;
- usbf_transfer_complete(xfer);
- CSR_SET_4(sc, USBDC_UDCCSR(ep), USBDC_UDCCSR_PC);
- return;
- }
- #ifdef DEBUG_RX
- printf("reading data from endpoint %x, len %x csr %x",
- ep, count, csr);
- #endif
- while (CSR_READ_4(sc, USBDC_UDCCSR(ep)) & USBDC_UDCCSR_BNE) {
- u_int32_t v = CSR_READ_4(sc, USBDC_UDCDR(ep));
- /* double buffering? */
- if (len > 0) {
- if (((unsigned)p & 0x3) == 0)
- *(u_int32_t *)p = v;
- else {
- *(p+0) = v & 0xff;
- *(p+1) = (v >> 8) & 0xff;
- *(p+2) = (v >> 16) & 0xff;
- *(p+3) = (v >> 24) & 0xff;
- }
- p += 4;
- len -= 4;
- xfer->actlen += 4;
- }
- count -= 4;
- }
- CSR_SET_4(sc, USBDC_UDCCSR(ep), USBDC_UDCCSR_PC);
- if (xfer->length == xfer->actlen || (tlen == 0 && xfer->actlen != 0) ||
- csr & USBDC_UDCCSR_SP) {
- #ifdef DEBUG_RX
- printf("trans2 complete\n");
- #endif
- xfer->status = USBF_NORMAL_COMPLETION;
- usbf_transfer_complete(xfer);
- }
- csr = CSR_READ_4(sc, USBDC_UDCCSR(ep));
- #ifdef DEBUG_RX
- printf("csr now %x len %x\n",
- csr, CSR_READ_4(sc, USBDC_UDCBCR(ep)));
- #endif
- if (csr & USBDC_UDCCSR_PC)
- goto again;
- }
- void
- pxaudc_write_ep0(struct pxaudc_softc *sc, struct usbf_xfer *xfer)
- {
- struct pxaudc_xfer *lxfer = (struct pxaudc_xfer *)xfer;
- u_int32_t len;
- u_int8_t *p;
- if (lxfer->frmlen > 0) {
- xfer->actlen += lxfer->frmlen;
- lxfer->frmlen = 0;
- }
- DPRINTF(11,("%s: ep0 ctrl-in, xfer=%p, len=%u, actlen=%u\n",
- DEVNAME(sc), xfer, xfer->length, xfer->actlen));
- if (xfer->actlen >= xfer->length) {
- sc->sc_ep0state = EP0_SETUP;
- usbf_transfer_complete(xfer);
- return;
- }
- sc->sc_ep0state = EP0_IN;
- p = (u_char *)xfer->buffer + xfer->actlen;
- len = xfer->length - xfer->actlen;
- len = MIN(len, PXAUDC_EP0MAXP);
- lxfer->frmlen = len;
- while (len >= 4) {
- u_int32_t v;
- if (((unsigned)p & 0x3) == 0)
- v = *(u_int32_t *)p;
- else {
- v = *(p+0);
- v |= *(p+1) << 8;
- v |= *(p+2) << 16;
- v |= *(p+3) << 24;
- }
- CSR_WRITE_4(sc, USBDC_UDCDR(0), v);
- len -= 4;
- p += 4;
- }
- while (len > 0) {
- CSR_WRITE_1(sc, USBDC_UDCDR(0), *p);
- len--;
- p++;
- }
- /* (12.6.7) Set IPR only for short packets. */
- if (lxfer->frmlen < PXAUDC_EP0MAXP)
- CSR_SET_4(sc, USBDC_UDCCSR0, USBDC_UDCCSR0_IPR);
- }
- void
- pxaudc_write(struct pxaudc_softc *sc, struct usbf_xfer *xfer)
- {
- u_int8_t *p;
- int ep = sc->sc_ep_map[usbf_endpoint_index(xfer->pipe->endpoint)];
- int tlen = 0;
- int maxp = UGETW(xfer->pipe->endpoint->edesc->wMaxPacketSize);
- u_int32_t csr, csr_o;
- #ifdef DEBUG_TX_PKT
- if (xfer->actlen == 0)
- printf("new packet len %x\n", xfer->length);
- #endif
- #ifdef DEBUG_TX
- printf("writing data to endpoint %x, xlen %x xact %x\n",
- ep, xfer->length, xfer->actlen);
- #endif
- if (xfer->actlen == xfer->length) {
- /*
- * If the packet size is wMaxPacketSize byte multiple
- * send a zero packet to indicate termiation.
- */
- if ((xfer->actlen % maxp) == 0 &&
- xfer->status != USBF_NORMAL_COMPLETION &&
- xfer->flags & USBD_FORCE_SHORT_XFER) {
- if (CSR_READ_4(sc, USBDC_UDCCSR(ep))
- & USBDC_UDCCSR_BNF) {
- CSR_SET_4(sc, USBDC_UDCCSR(ep),
- USBDC_UDCCSR_SP);
- /*
- * if we send a zero packet, we are 'done', but
- * dont to usbf_transfer_complete() just yet
- * because the short packet will cause another
- * interrupt.
- */
- xfer->status = USBF_NORMAL_COMPLETION;
- return;
- } else {
- printf("fifo full when trying to set short packet\n");
- }
- }
- xfer->status = USBF_NORMAL_COMPLETION;
- #ifdef DEBUG_TX_PKT
- printf("packet complete %x\n", xfer->actlen);
- #endif
- usbf_transfer_complete(xfer);
- return;
- }
- p = xfer->buffer + xfer->actlen;
- csr_o = 0;
- csr = CSR_READ_4(sc, USBDC_UDCCSR(ep));
- if (csr & USBDC_UDCCSR_PC)
- csr_o |= USBDC_UDCCSR_PC;
- if (csr & USBDC_UDCCSR_TRN)
- csr_o |= USBDC_UDCCSR_TRN;
- if (csr & USBDC_UDCCSR_SST)
- csr_o |= USBDC_UDCCSR_SST;
- if (csr_o != 0)
- CSR_WRITE_4(sc, USBDC_UDCCSR(ep), csr_o);
- while (CSR_READ_4(sc, USBDC_UDCCSR(ep)) & USBDC_UDCCSR_BNF) {
- u_int32_t v;
- if (xfer->length - xfer->actlen < 4) {
- while (xfer->actlen < xfer->length) {
- CSR_WRITE_1(sc, USBDC_UDCDR(ep), *p);
- p++;
- xfer->actlen++;
- tlen++;
- }
- break;
- }
- if (((unsigned)p & 0x3) == 0)
- v = *(u_int32_t *)p;
- else {
- v = *(p+0);
- v |= *(p+1) << 8;
- v |= *(p+2) << 16;
- v |= *(p+3) << 24;
- }
- CSR_WRITE_4(sc, USBDC_UDCDR(ep), v);
- p += 4;
- xfer->actlen += 4;
- tlen += 4;
- }
- #ifdef DEBUG_TX
- printf(" wrote tlen %x %x\n", tlen, xfer->actlen);
- if (xfer->actlen == 0) {
- printf("whoa, write_ep called, but no free space\n");
- }
- #endif
- if (xfer->actlen == xfer->length) {
- if ((xfer->actlen % maxp) != 0) {
- if (xfer->flags & USBD_FORCE_SHORT_XFER) {
- CSR_SET_4(sc, USBDC_UDCCSR(ep), USBDC_UDCCSR_SP);
- #ifdef DEBUG_TX
- printf("setting short packet on %x csr\n", ep,
- CSR_READ_4(sc, USBDC_UDCCSR(ep)));
- #endif
- } else {
- /* fill buffer to maxpacket size??? */
- }
- }
- }
- }
- /*
- * Interrupt handling
- */
- int
- pxaudc_connect_intr(void *v)
- {
- struct pxaudc_softc *sc = v;
- DPRINTF(10,("pxaudc_connect_intr: connect=%d\n",
- pxa2x0_gpio_get_bit(sc->sc_gpio_detect)));
- /* XXX only set a flag here */
- if (sc->sc_is_host()) {
- #if 0
- printf("%s:switching to host\n", sc->sc_bus.bdev.dv_xname);
- #endif
- pxaudc_disable(sc);
- } else {
- #if 0
- printf("%s:switching to client\n", sc->sc_bus.bdev.dv_xname);
- #endif
- pxaudc_enable(sc);
- }
- /* Claim this interrupt. */
- return 1;
- }
- int
- pxaudc_intr(void *v)
- {
- struct pxaudc_softc *sc = v;
- u_int32_t isr0, isr1, otgisr;
- isr0 = CSR_READ_4(sc, USBDC_UDCISR0);
- isr1 = CSR_READ_4(sc, USBDC_UDCISR1);
- otgisr = CSR_READ_4(sc, USBDC_UDCOTGISR);
- DPRINTF(10,("pxaudc_intr: isr0=%b, isr1=%b, otgisr=%b\n",
- isr0, USBDC_UDCISR0_BITS, isr1, USBDC_UDCISR1_BITS,
- otgisr, USBDC_UDCOTGISR_BITS));
- if (isr0 || isr1 || otgisr) {
- sc->sc_isr0 |= isr0;
- sc->sc_isr1 |= isr1;
- sc->sc_otgisr |= otgisr;
- //usbf_schedsoftintr(&sc->sc_bus);
- pxaudc_intr1(sc); /* XXX */
- }
- CSR_WRITE_4(sc, USBDC_UDCISR0, isr0);
- CSR_WRITE_4(sc, USBDC_UDCISR1, isr1);
- CSR_WRITE_4(sc, USBDC_UDCOTGISR, otgisr);
- /* Claim this interrupt. */
- return 1;
- }
- u_int32_t csr1, csr2;
- void
- pxaudc_intr1(struct pxaudc_softc *sc)
- {
- u_int32_t isr0, isr1, otgisr;
- int i;
- //int s;
- //s = splhardusb();
- isr0 = sc->sc_isr0;
- isr1 = sc->sc_isr1;
- otgisr = sc->sc_otgisr;
- sc->sc_isr0 = 0;
- sc->sc_isr1 = 0;
- sc->sc_otgisr = 0;
- //splx(s);
- sc->sc_bus.intr_context++;
- if (isr1 & USBDC_UDCISR1_IRCC) {
- u_int32_t ccr;
- CSR_SET_4(sc, USBDC_UDCCR, USBDC_UDCCR_SMAC);
- /* wait for reconfig to finish (SMAC auto clears) */
- while (CSR_READ_4(sc, USBDC_UDCCR) & USBDC_UDCCR_SMAC)
- delay(10);
- ccr = CSR_READ_4(sc, USBDC_UDCCR);
- sc->sc_cn = USBDC_UDCCR_ACNr(ccr);
- sc->sc_in = USBDC_UDCCR_AINr(ccr);
- sc->sc_isn = USBDC_UDCCR_AAISNr(ccr);
- goto ret;
- }
- #if 0
- printf("pxaudc_intr: isr0=%b, isr1=%b, otgisr=%b\n",
- isr0, USBDC_UDCISR0_BITS, isr1, USBDC_UDCISR1_BITS,
- otgisr, USBDC_UDCOTGISR_BITS);
- #endif
- /* Handle USB RESET condition. */
- if (isr1 & USBDC_UDCISR1_IRRS) {
- sc->sc_ep0state = EP0_SETUP;
- usbf_host_reset(&sc->sc_bus);
- /* Discard all other interrupts. */
- goto ret;
- }
- /* Service control pipe interrupts. */
- if (isr0 & USBDC_UDCISR0_IR(0))
- pxaudc_ep0_intr(sc);
- for (i = 1; i < 24; i++) {
- if (i < 16) {
- if (USBDC_UDCISR0_IRs(isr0,i))
- pxaudc_epN_intr(sc, i,
- USBDC_UDCISR0_IRs(isr0,i));
- } else {
- if (USBDC_UDCISR1_IRs(isr1,i))
- pxaudc_epN_intr(sc, i,
- USBDC_UDCISR1_IRs(isr1,i));
- }
- }
- if (isr1 & USBDC_UDCISR1_IRSU) {
- /* suspend ?? */
- }
- if (isr1 & USBDC_UDCISR1_IRRU) {
- /* resume ?? */
- }
- ret:
- sc->sc_bus.intr_context--;
- }
- void
- pxaudc_epN_intr(struct pxaudc_softc *sc, int ep, int isr)
- {
- struct pxaudc_pipe *ppipe;
- struct usbf_pipe *pipe;
- int dir;
- /* should not occur before device is configured */
- if (sc->sc_cn == 0)
- return;
- if (isr & 2)
- printf("ep%d: fifo error\n", ep); /* XXX */
- /* faster method of determining direction? */
- ppipe = sc->sc_pipe[ep];
- if (ppipe == NULL)
- return;
- pipe = &ppipe->pipe;
- dir = usbf_endpoint_dir(pipe->endpoint);
- if (dir == UE_DIR_IN) {
- pxaudc_write_epN(sc, ep);
- } else {
- pxaudc_read_epN(sc, ep);
- }
- }
- void
- pxaudc_write_epN(struct pxaudc_softc *sc, int ep)
- {
- struct pxaudc_pipe *ppipe;
- struct usbf_pipe *pipe = NULL;
- struct usbf_xfer *xfer = NULL;
- ppipe = sc->sc_pipe[ep];
- if (ppipe == NULL) {
- return;
- }
- pipe = &ppipe->pipe;
- xfer = SIMPLEQ_FIRST(&pipe->queue);
- if (xfer != NULL)
- pxaudc_write(sc, xfer);
- }
- void
- pxaudc_ep0_intr(struct pxaudc_softc *sc)
- {
- struct pxaudc_pipe *ppipe;
- struct usbf_pipe *pipe = NULL;
- struct usbf_xfer *xfer = NULL;
- u_int32_t csr0;
- csr0 = CSR_READ_4(sc, USBDC_UDCCSR0);
- DPRINTF(10,("pxaudc_ep0_intr: csr0=%b\n", csr0, USBDC_UDCCSR0_BITS));
- delay (25);
- ppipe = sc->sc_pipe[0];
- if (ppipe != NULL) {
- pipe = &ppipe->pipe;
- xfer = SIMPLEQ_FIRST(&pipe->queue);
- }
- if (sc->sc_ep0state == EP0_SETUP && (csr0 & USBDC_UDCCSR0_OPC)) {
- if (pipe == NULL) {
- DPRINTF(10,("pxaudc_ep0_intr: no control pipe\n"));
- return;
- }
- if (xfer == NULL) {
- DPRINTF(10,("pxaudc_ep0_intr: no xfer\n"));
- return;
- }
- pxaudc_read_ep0(sc, xfer);
- } else if (sc->sc_ep0state == EP0_IN &&
- (csr0 & USBDC_UDCCSR0_IPR) == 0 && xfer) {
- pxaudc_write_ep0(sc, xfer);
- }
- }
- /*
- * Bus methods
- */
- usbf_status
- pxaudc_open(struct usbf_pipe *pipe)
- {
- struct pxaudc_softc *sc = (struct pxaudc_softc *)pipe->device->bus;
- struct pxaudc_pipe *ppipe = (struct pxaudc_pipe *)pipe;
- int ep_idx;
- int s;
- ep_idx = usbf_endpoint_index(pipe->endpoint);
- if (ep_idx >= PXAUDC_NEP)
- return USBF_BAD_ADDRESS;
- DPRINTF(10,("pxaudc_open\n"));
- s = splhardusb();
- switch (usbf_endpoint_type(pipe->endpoint)) {
- case UE_CONTROL:
- pipe->methods = &pxaudc_ctrl_methods;
- break;
- case UE_BULK:
- pipe->methods = &pxaudc_bulk_methods;
- break;
- case UE_ISOCHRONOUS:
- case UE_INTERRUPT:
- default:
- /* XXX */
- splx(s);
- return USBF_BAD_ADDRESS;
- }
-
- if (ep_idx != 0 && sc->sc_ep_map[ep_idx] != -1) {
- printf("endpoint %d already used by %c",
- ep_idx, '@'+ sc->sc_ep_map[0]);
- splx(s);
- return USBF_BAD_ADDRESS;
- }
- sc->sc_ep_map[ep_idx] = sc->sc_npipe;
- sc->sc_pipe[sc->sc_npipe] = ppipe;
- sc->sc_npipe++;
- splx(s);
- return USBF_NORMAL_COMPLETION;
- }
- void
- pxaudc_softintr(void *v)
- {
- struct pxaudc_softc *sc = v;
- pxaudc_intr1(sc);
- }
- usbf_status
- pxaudc_allocm(struct usbf_bus *bus, struct usb_dma *dmap, u_int32_t size)
- {
- return usbf_allocmem(bus, size, 0, dmap);
- }
- void
- pxaudc_freem(struct usbf_bus *bus, struct usb_dma *dmap)
- {
- usbf_freemem(bus, dmap);
- }
- struct usbf_xfer *
- pxaudc_allocx(struct usbf_bus *bus)
- {
- struct pxaudc_softc *sc = (struct pxaudc_softc *)bus;
- struct usbf_xfer *xfer;
- xfer = SIMPLEQ_FIRST(&sc->sc_free_xfers);
- if (xfer != NULL)
- SIMPLEQ_REMOVE_HEAD(&sc->sc_free_xfers, next);
- else
- xfer = malloc(sizeof(struct pxaudc_xfer), M_USB, M_NOWAIT);
- if (xfer != NULL)
- bzero(xfer, sizeof(struct pxaudc_xfer));
- return xfer;
- }
- void
- pxaudc_freex(struct usbf_bus *bus, struct usbf_xfer *xfer)
- {
- struct pxaudc_softc *sc = (struct pxaudc_softc *)bus;
- SIMPLEQ_INSERT_HEAD(&sc->sc_free_xfers, xfer, next);
- }
- /*
- * Control pipe methods
- */
- usbf_status
- pxaudc_ctrl_transfer(struct usbf_xfer *xfer)
- {
- usbf_status err;
- /* Insert last in queue. */
- err = usbf_insert_transfer(xfer);
- if (err)
- return err;
- /*
- * Pipe isn't running (otherwise err would be USBF_IN_PROGRESS),
- * so start first.
- */
- return pxaudc_ctrl_start(SIMPLEQ_FIRST(&xfer->pipe->queue));
- }
- usbf_status
- pxaudc_ctrl_start(struct usbf_xfer *xfer)
- {
- struct usbf_pipe *pipe = xfer->pipe;
- struct pxaudc_softc *sc = (struct pxaudc_softc *)pipe->device->bus;
- int iswrite = !(xfer->rqflags & URQ_REQUEST);
- int s;
- s = splusb();
- xfer->status = USBF_IN_PROGRESS;
- if (iswrite)
- pxaudc_write_ep0(sc, xfer);
- else {
- /* XXX boring message, this case is normally reached if
- * XXX the xfer for a device request is being queued. */
- DPRINTF(10,("%s: ep[%x] ctrl-out, xfer=%p, len=%u, "
- "actlen=%u\n", DEVNAME(sc),
- usbf_endpoint_address(xfer->pipe->endpoint),
- xfer, xfer->length,
- xfer->actlen));
- }
- splx(s);
- return USBF_IN_PROGRESS;
- }
- /* (also used by bulk pipes) */
- void
- pxaudc_ctrl_abort(struct usbf_xfer *xfer)
- {
- int s;
- #ifdef PXAUDC_DEBUG
- struct usbf_pipe *pipe = xfer->pipe;
- struct pxaudc_softc *sc = (struct pxaudc_softc *)pipe->device->bus;
- int index = usbf_endpoint_index(pipe->endpoint);
- int dir = usbf_endpoint_dir(pipe->endpoint);
- int type = usbf_endpoint_type(pipe->endpoint);
- #endif
- DPRINTF(10,("%s: ep%d %s-%s abort, xfer=%p\n", DEVNAME(sc), index,
- type == UE_CONTROL ? "ctrl" : "bulk", dir == UE_DIR_IN ?
- "in" : "out", xfer));
- /*
- * Step 1: Make soft interrupt routine and hardware ignore the xfer.
- */
- s = splusb();
- xfer->status = USBF_CANCELLED;
- timeout_del(&xfer->timeout_handle);
- splx(s);
- /*
- * Step 2: Make sure hardware has finished any possible use of the
- * xfer and the soft interrupt routine has run.
- */
- s = splusb();
- /* XXX this does not seem right, what if there
- * XXX are two xfers in the FIFO and we only want to
- * XXX ignore one? */
- #ifdef notyet
- pxaudc_flush(sc, usbf_endpoint_address(pipe->endpoint));
- #endif
- /* XXX we're not doing DMA and the soft interrupt routine does not
- XXX need to clean up anything. */
- splx(s);
- /*
- * Step 3: Execute callback.
- */
- s = splusb();
- usbf_transfer_complete(xfer);
- splx(s);
- }
- void
- pxaudc_ctrl_done(struct usbf_xfer *xfer)
- {
- }
- void
- pxaudc_ctrl_close(struct usbf_pipe *pipe)
- {
- /* XXX */
- }
- /*
- * Bulk pipe methods
- */
- usbf_status
- pxaudc_bulk_transfer(struct usbf_xfer *xfer)
- {
- usbf_status err;
- /* Insert last in queue. */
- err = usbf_insert_transfer(xfer);
- if (err)
- return err;
- /*
- * Pipe isn't running (otherwise err would be USBF_IN_PROGRESS),
- * so start first.
- */
- return pxaudc_bulk_start(SIMPLEQ_FIRST(&xfer->pipe->queue));
- }
- usbf_status
- pxaudc_bulk_start(struct usbf_xfer *xfer)
- {
- struct usbf_pipe *pipe = xfer->pipe;
- struct pxaudc_softc *sc = (struct pxaudc_softc *)pipe->device->bus;
- int iswrite = (usbf_endpoint_dir(pipe->endpoint) == UE_DIR_IN);
- int s;
- DPRINTF(0,("%s: ep%d bulk-%s start, xfer=%p, len=%u\n", DEVNAME(sc),
- usbf_endpoint_index(pipe->endpoint), iswrite ? "in" : "out",
- xfer, xfer->length));
- s = splusb();
- xfer->status = USBF_IN_PROGRESS;
- if (iswrite)
- pxaudc_write(sc, xfer);
- else {
- /* enable interrupt */
- }
- splx(s);
- return USBF_IN_PROGRESS;
- }
- void
- pxaudc_bulk_abort(struct usbf_xfer *xfer)
- {
- pxaudc_ctrl_abort(xfer);
- }
- void
- pxaudc_bulk_done(struct usbf_xfer *xfer)
- {
- #if 0
- int ep = usbf_endpoint_address(xfer->pipe->endpoint);
- struct usbf_pipe *pipe = xfer->pipe;
- struct pxaudc_softc *sc = (struct pxaudc_softc *)pipe->device->bus;
- #endif
- }
- void
- pxaudc_bulk_close(struct usbf_pipe *pipe)
- {
- /* XXX */
- }
- #endif /* NUSBF > 0 */
|