1184610Salfred/* $FreeBSD$ */ 2184610Salfred/*- 3184610Salfred * Copyright (c) 2008 Hans Petter Selasky. All rights reserved. 4184610Salfred * 5184610Salfred * Redistribution and use in source and binary forms, with or without 6184610Salfred * modification, are permitted provided that the following conditions 7184610Salfred * are met: 8184610Salfred * 1. Redistributions of source code must retain the above copyright 9184610Salfred * notice, this list of conditions and the following disclaimer. 10184610Salfred * 2. Redistributions in binary form must reproduce the above copyright 11184610Salfred * notice, this list of conditions and the following disclaimer in the 12184610Salfred * documentation and/or other materials provided with the distribution. 13184610Salfred * 14184610Salfred * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15184610Salfred * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16184610Salfred * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17184610Salfred * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18184610Salfred * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19184610Salfred * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20184610Salfred * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21184610Salfred * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22184610Salfred * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23184610Salfred * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24184610Salfred * SUCH DAMAGE. 25184610Salfred */ 26184610Salfred 27184610Salfred/* 28190754Sthompsa * Thanks to Mentor Graphics for providing a reference driver for this USB chip 29190754Sthompsa * at their homepage. 30184610Salfred */ 31184610Salfred 32184610Salfred/* 33184610Salfred * This file contains the driver for the Mentor Graphics Inventra USB 34184610Salfred * 2.0 High Speed Dual-Role controller. 35184610Salfred * 36184610Salfred * NOTE: The current implementation only supports Device Side Mode! 37184610Salfred */ 38184610Salfred 39246122Shselasky#ifdef USB_GLOBAL_INCLUDE_FILE 40246122Shselasky#include USB_GLOBAL_INCLUDE_FILE 41246122Shselasky#else 42194677Sthompsa#include <sys/stdint.h> 43194677Sthompsa#include <sys/stddef.h> 44194677Sthompsa#include <sys/param.h> 45194677Sthompsa#include <sys/queue.h> 46194677Sthompsa#include <sys/types.h> 47194677Sthompsa#include <sys/systm.h> 48194677Sthompsa#include <sys/kernel.h> 49194677Sthompsa#include <sys/bus.h> 50194677Sthompsa#include <sys/module.h> 51194677Sthompsa#include <sys/lock.h> 52194677Sthompsa#include <sys/mutex.h> 53194677Sthompsa#include <sys/condvar.h> 54194677Sthompsa#include <sys/sysctl.h> 55194677Sthompsa#include <sys/sx.h> 56194677Sthompsa#include <sys/unistd.h> 57194677Sthompsa#include <sys/callout.h> 58194677Sthompsa#include <sys/malloc.h> 59194677Sthompsa#include <sys/priv.h> 60194677Sthompsa 61188942Sthompsa#include <dev/usb/usb.h> 62194677Sthompsa#include <dev/usb/usbdi.h> 63184610Salfred 64184610Salfred#define USB_DEBUG_VAR musbotgdebug 65184610Salfred 66188942Sthompsa#include <dev/usb/usb_core.h> 67188942Sthompsa#include <dev/usb/usb_debug.h> 68188942Sthompsa#include <dev/usb/usb_busdma.h> 69188942Sthompsa#include <dev/usb/usb_process.h> 70188942Sthompsa#include <dev/usb/usb_transfer.h> 71188942Sthompsa#include <dev/usb/usb_device.h> 72188942Sthompsa#include <dev/usb/usb_hub.h> 73188942Sthompsa#include <dev/usb/usb_util.h> 74184610Salfred 75188942Sthompsa#include <dev/usb/usb_controller.h> 76188942Sthompsa#include <dev/usb/usb_bus.h> 77246122Shselasky#endif /* USB_GLOBAL_INCLUDE_FILE */ 78246122Shselasky 79188942Sthompsa#include <dev/usb/controller/musb_otg.h> 80184610Salfred 81184610Salfred#define MUSBOTG_INTR_ENDPT 1 82184610Salfred 83184610Salfred#define MUSBOTG_BUS2SC(bus) \ 84184610Salfred ((struct musbotg_softc *)(((uint8_t *)(bus)) - \ 85184610Salfred USB_P2U(&(((struct musbotg_softc *)0)->sc_bus)))) 86184610Salfred 87184610Salfred#define MUSBOTG_PC2SC(pc) \ 88190180Sthompsa MUSBOTG_BUS2SC(USB_DMATAG_TO_XROOT((pc)->tag_parent)->bus) 89184610Salfred 90194677Sthompsa#ifdef USB_DEBUG 91184610Salfredstatic int musbotgdebug = 0; 92184610Salfred 93227309Sedstatic SYSCTL_NODE(_hw_usb, OID_AUTO, musbotg, CTLFLAG_RW, 0, "USB musbotg"); 94192502SthompsaSYSCTL_INT(_hw_usb_musbotg, OID_AUTO, debug, CTLFLAG_RW, 95184610Salfred &musbotgdebug, 0, "Debug level"); 96184610Salfred#endif 97184610Salfred 98252912Sgonzo#define MAX_NAK_TO 16 99252912Sgonzo 100184610Salfred/* prototypes */ 101184610Salfred 102192984Sthompsastruct usb_bus_methods musbotg_bus_methods; 103192984Sthompsastruct usb_pipe_methods musbotg_device_bulk_methods; 104192984Sthompsastruct usb_pipe_methods musbotg_device_ctrl_methods; 105192984Sthompsastruct usb_pipe_methods musbotg_device_intr_methods; 106192984Sthompsastruct usb_pipe_methods musbotg_device_isoc_methods; 107184610Salfred 108252912Sgonzo/* Control transfers: Device mode */ 109252912Sgonzostatic musbotg_cmd_t musbotg_dev_ctrl_setup_rx; 110252912Sgonzostatic musbotg_cmd_t musbotg_dev_ctrl_data_rx; 111252912Sgonzostatic musbotg_cmd_t musbotg_dev_ctrl_data_tx; 112252912Sgonzostatic musbotg_cmd_t musbotg_dev_ctrl_status; 113252912Sgonzo 114252912Sgonzo/* Control transfers: Host mode */ 115252912Sgonzostatic musbotg_cmd_t musbotg_host_ctrl_setup_tx; 116252912Sgonzostatic musbotg_cmd_t musbotg_host_ctrl_data_rx; 117252912Sgonzostatic musbotg_cmd_t musbotg_host_ctrl_data_tx; 118252912Sgonzostatic musbotg_cmd_t musbotg_host_ctrl_status_rx; 119252912Sgonzostatic musbotg_cmd_t musbotg_host_ctrl_status_tx; 120252912Sgonzo 121252912Sgonzo/* Bulk, Interrupt, Isochronous: Device mode */ 122252912Sgonzostatic musbotg_cmd_t musbotg_dev_data_rx; 123252912Sgonzostatic musbotg_cmd_t musbotg_dev_data_tx; 124252912Sgonzo 125252912Sgonzo/* Bulk, Interrupt, Isochronous: Host mode */ 126252912Sgonzostatic musbotg_cmd_t musbotg_host_data_rx; 127252912Sgonzostatic musbotg_cmd_t musbotg_host_data_tx; 128252912Sgonzo 129193045Sthompsastatic void musbotg_device_done(struct usb_xfer *, usb_error_t); 130192984Sthompsastatic void musbotg_do_poll(struct usb_bus *); 131192984Sthompsastatic void musbotg_standard_done(struct usb_xfer *); 132185948Sthompsastatic void musbotg_interrupt_poll(struct musbotg_softc *); 133190735Sthompsastatic void musbotg_root_intr(struct musbotg_softc *); 134252912Sgonzostatic int musbotg_channel_alloc(struct musbotg_softc *, struct musbotg_td *td); 135252912Sgonzostatic void musbotg_channel_free(struct musbotg_softc *, struct musbotg_td *td); 136252912Sgonzostatic void musbotg_ep_int_set(struct musbotg_softc *sc, int channel, int on); 137184610Salfred 138184610Salfred/* 139184610Salfred * Here is a configuration that the chip supports. 140184610Salfred */ 141192984Sthompsastatic const struct usb_hw_ep_profile musbotg_ep_profile[1] = { 142184610Salfred 143184610Salfred [0] = { 144184610Salfred .max_in_frame_size = 64,/* fixed */ 145184610Salfred .max_out_frame_size = 64, /* fixed */ 146184610Salfred .is_simplex = 1, 147184610Salfred .support_control = 1, 148184610Salfred } 149184610Salfred}; 150184610Salfred 151252912Sgonzostatic int 152252912Sgonzomusbotg_channel_alloc(struct musbotg_softc *sc, struct musbotg_td *td) 153252912Sgonzo{ 154252912Sgonzo int ch; 155252912Sgonzo int ep; 156252912Sgonzo 157252912Sgonzo ep = td->ep_no; 158252912Sgonzo 159252912Sgonzo /* In device mode each EP got its own channel */ 160252912Sgonzo if (sc->sc_mode == MUSB2_DEVICE_MODE) { 161252912Sgonzo musbotg_ep_int_set(sc, ep, 1); 162252912Sgonzo return (ep); 163252912Sgonzo } 164252912Sgonzo 165252912Sgonzo /* 166252912Sgonzo * All control transactions go through EP0 167252912Sgonzo */ 168252912Sgonzo if (ep == 0) { 169252912Sgonzo if (sc->sc_channel_mask & (1 << 0)) 170252912Sgonzo return (-1); 171252912Sgonzo sc->sc_channel_mask |= (1 << 0); 172252912Sgonzo musbotg_ep_int_set(sc, ep, 1); 173252912Sgonzo return (0); 174252912Sgonzo } 175252912Sgonzo 176252912Sgonzo for (ch = 1; ch < MUSB2_EP_MAX; ch++) { 177252912Sgonzo if (!(sc->sc_channel_mask & (1 << ch))) { 178252912Sgonzo sc->sc_channel_mask |= (1 << ch); 179252912Sgonzo musbotg_ep_int_set(sc, ch, 1); 180252912Sgonzo return (ch); 181252912Sgonzo } 182252912Sgonzo } 183252912Sgonzo 184252912Sgonzo DPRINTFN(-1, "No available channels. Mask: %04x\n", sc->sc_channel_mask); 185252912Sgonzo 186252912Sgonzo return (-1); 187252912Sgonzo} 188252912Sgonzo 189252912Sgonzostatic void 190252912Sgonzomusbotg_channel_free(struct musbotg_softc *sc, struct musbotg_td *td) 191252912Sgonzo{ 192252912Sgonzo 193252912Sgonzo DPRINTFN(1, "ep_no=%d\n", td->channel); 194252912Sgonzo 195252912Sgonzo if (sc->sc_mode == MUSB2_DEVICE_MODE) 196252912Sgonzo return; 197252912Sgonzo 198252912Sgonzo if (td == NULL) 199252912Sgonzo return; 200252912Sgonzo if (td->channel == -1) 201252912Sgonzo return; 202252912Sgonzo 203252912Sgonzo musbotg_ep_int_set(sc, td->channel, 0); 204252912Sgonzo sc->sc_channel_mask &= ~(1 << td->channel); 205252912Sgonzo 206252912Sgonzo td->channel = -1; 207252912Sgonzo} 208252912Sgonzo 209184610Salfredstatic void 210192984Sthompsamusbotg_get_hw_ep_profile(struct usb_device *udev, 211192984Sthompsa const struct usb_hw_ep_profile **ppf, uint8_t ep_addr) 212184610Salfred{ 213184610Salfred struct musbotg_softc *sc; 214184610Salfred 215184610Salfred sc = MUSBOTG_BUS2SC(udev->bus); 216184610Salfred 217184610Salfred if (ep_addr == 0) { 218184610Salfred /* control endpoint */ 219184610Salfred *ppf = musbotg_ep_profile; 220184610Salfred } else if (ep_addr <= sc->sc_ep_max) { 221184610Salfred /* other endpoints */ 222184610Salfred *ppf = sc->sc_hw_ep_profile + ep_addr; 223184610Salfred } else { 224184610Salfred *ppf = NULL; 225184610Salfred } 226184610Salfred} 227184610Salfred 228184610Salfredstatic void 229184610Salfredmusbotg_clocks_on(struct musbotg_softc *sc) 230184610Salfred{ 231184610Salfred if (sc->sc_flags.clocks_off && 232184610Salfred sc->sc_flags.port_powered) { 233184610Salfred 234184610Salfred DPRINTFN(4, "\n"); 235184610Salfred 236184610Salfred if (sc->sc_clocks_on) { 237184610Salfred (sc->sc_clocks_on) (sc->sc_clocks_arg); 238184610Salfred } 239184610Salfred sc->sc_flags.clocks_off = 0; 240184610Salfred 241184610Salfred /* XXX enable Transceiver */ 242184610Salfred } 243184610Salfred} 244184610Salfred 245184610Salfredstatic void 246184610Salfredmusbotg_clocks_off(struct musbotg_softc *sc) 247184610Salfred{ 248184610Salfred if (!sc->sc_flags.clocks_off) { 249184610Salfred 250184610Salfred DPRINTFN(4, "\n"); 251184610Salfred 252184610Salfred /* XXX disable Transceiver */ 253184610Salfred 254184610Salfred if (sc->sc_clocks_off) { 255184610Salfred (sc->sc_clocks_off) (sc->sc_clocks_arg); 256184610Salfred } 257184610Salfred sc->sc_flags.clocks_off = 1; 258184610Salfred } 259184610Salfred} 260184610Salfred 261184610Salfredstatic void 262184610Salfredmusbotg_pull_common(struct musbotg_softc *sc, uint8_t on) 263184610Salfred{ 264184610Salfred uint8_t temp; 265184610Salfred 266184610Salfred temp = MUSB2_READ_1(sc, MUSB2_REG_POWER); 267184610Salfred if (on) 268184610Salfred temp |= MUSB2_MASK_SOFTC; 269184610Salfred else 270184610Salfred temp &= ~MUSB2_MASK_SOFTC; 271184610Salfred 272184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_POWER, temp); 273184610Salfred} 274184610Salfred 275184610Salfredstatic void 276184610Salfredmusbotg_pull_up(struct musbotg_softc *sc) 277184610Salfred{ 278184610Salfred /* pullup D+, if possible */ 279184610Salfred 280184610Salfred if (!sc->sc_flags.d_pulled_up && 281184610Salfred sc->sc_flags.port_powered) { 282184610Salfred sc->sc_flags.d_pulled_up = 1; 283184610Salfred musbotg_pull_common(sc, 1); 284184610Salfred } 285184610Salfred} 286184610Salfred 287184610Salfredstatic void 288184610Salfredmusbotg_pull_down(struct musbotg_softc *sc) 289184610Salfred{ 290184610Salfred /* pulldown D+, if possible */ 291184610Salfred 292184610Salfred if (sc->sc_flags.d_pulled_up) { 293184610Salfred sc->sc_flags.d_pulled_up = 0; 294184610Salfred musbotg_pull_common(sc, 0); 295184610Salfred } 296184610Salfred} 297184610Salfred 298184610Salfredstatic void 299252912Sgonzomusbotg_suspend_host(struct musbotg_softc *sc) 300252912Sgonzo{ 301252912Sgonzo uint8_t temp; 302252912Sgonzo 303252912Sgonzo if (sc->sc_flags.status_suspend) { 304252912Sgonzo return; 305252912Sgonzo } 306252912Sgonzo 307252912Sgonzo temp = MUSB2_READ_1(sc, MUSB2_REG_POWER); 308252912Sgonzo temp |= MUSB2_MASK_SUSPMODE; 309252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_POWER, temp); 310252912Sgonzo sc->sc_flags.status_suspend = 1; 311252912Sgonzo} 312252912Sgonzo 313252912Sgonzostatic void 314252912Sgonzomusbotg_wakeup_host(struct musbotg_softc *sc) 315252912Sgonzo{ 316252912Sgonzo uint8_t temp; 317252912Sgonzo 318252912Sgonzo if (!(sc->sc_flags.status_suspend)) { 319252912Sgonzo return; 320252912Sgonzo } 321252912Sgonzo 322252912Sgonzo temp = MUSB2_READ_1(sc, MUSB2_REG_POWER); 323252912Sgonzo temp &= ~MUSB2_MASK_SUSPMODE; 324252912Sgonzo temp |= MUSB2_MASK_RESUME; 325252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_POWER, temp); 326252912Sgonzo 327252912Sgonzo /* wait 20 milliseconds */ 328252912Sgonzo /* Wait for reset to complete. */ 329252912Sgonzo usb_pause_mtx(&sc->sc_bus.bus_mtx, hz / 50); 330252912Sgonzo 331252912Sgonzo temp = MUSB2_READ_1(sc, MUSB2_REG_POWER); 332252912Sgonzo temp &= ~MUSB2_MASK_RESUME; 333252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_POWER, temp); 334252912Sgonzo 335252912Sgonzo sc->sc_flags.status_suspend = 0; 336252912Sgonzo} 337252912Sgonzo 338252912Sgonzostatic void 339190735Sthompsamusbotg_wakeup_peer(struct musbotg_softc *sc) 340184610Salfred{ 341184610Salfred uint8_t temp; 342184610Salfred 343184610Salfred if (!(sc->sc_flags.status_suspend)) { 344184610Salfred return; 345184610Salfred } 346184610Salfred 347184610Salfred temp = MUSB2_READ_1(sc, MUSB2_REG_POWER); 348184610Salfred temp |= MUSB2_MASK_RESUME; 349184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_POWER, temp); 350184610Salfred 351184610Salfred /* wait 8 milliseconds */ 352188983Sthompsa /* Wait for reset to complete. */ 353194228Sthompsa usb_pause_mtx(&sc->sc_bus.bus_mtx, hz / 125); 354184610Salfred 355184610Salfred temp = MUSB2_READ_1(sc, MUSB2_REG_POWER); 356184610Salfred temp &= ~MUSB2_MASK_RESUME; 357184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_POWER, temp); 358184610Salfred} 359184610Salfred 360184610Salfredstatic void 361184610Salfredmusbotg_set_address(struct musbotg_softc *sc, uint8_t addr) 362184610Salfred{ 363184610Salfred DPRINTFN(4, "addr=%d\n", addr); 364184610Salfred addr &= 0x7F; 365184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_FADDR, addr); 366184610Salfred} 367184610Salfred 368184610Salfredstatic uint8_t 369252912Sgonzomusbotg_dev_ctrl_setup_rx(struct musbotg_td *td) 370184610Salfred{ 371184610Salfred struct musbotg_softc *sc; 372192984Sthompsa struct usb_device_request req; 373184610Salfred uint16_t count; 374184610Salfred uint8_t csr; 375184610Salfred 376184610Salfred /* get pointer to softc */ 377184610Salfred sc = MUSBOTG_PC2SC(td->pc); 378184610Salfred 379252912Sgonzo if (td->channel == -1) 380252912Sgonzo td->channel = musbotg_channel_alloc(sc, td); 381252912Sgonzo 382252912Sgonzo /* EP0 is busy, wait */ 383252912Sgonzo if (td->channel == -1) 384252912Sgonzo return (1); 385252912Sgonzo 386252912Sgonzo DPRINTFN(1, "ep_no=%d\n", td->channel); 387252912Sgonzo 388184610Salfred /* select endpoint 0 */ 389184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_EPINDEX, 0); 390184610Salfred 391184610Salfred /* read out FIFO status */ 392184610Salfred csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL); 393184610Salfred 394184610Salfred DPRINTFN(4, "csr=0x%02x\n", csr); 395184610Salfred 396184610Salfred /* 397184610Salfred * NOTE: If DATAEND is set we should not call the 398184610Salfred * callback, hence the status stage is not complete. 399184610Salfred */ 400184610Salfred if (csr & MUSB2_MASK_CSR0L_DATAEND) { 401190721Sthompsa /* do not stall at this point */ 402190721Sthompsa td->did_stall = 1; 403184610Salfred /* wait for interrupt */ 404252912Sgonzo DPRINTFN(0, "CSR0 DATAEND\n"); 405184610Salfred goto not_complete; 406184610Salfred } 407252912Sgonzo 408184610Salfred if (csr & MUSB2_MASK_CSR0L_SENTSTALL) { 409184610Salfred /* clear SENTSTALL */ 410184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 0); 411184610Salfred /* get latest status */ 412184610Salfred csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL); 413184610Salfred /* update EP0 state */ 414184610Salfred sc->sc_ep0_busy = 0; 415184610Salfred } 416184610Salfred if (csr & MUSB2_MASK_CSR0L_SETUPEND) { 417184610Salfred /* clear SETUPEND */ 418184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 419184610Salfred MUSB2_MASK_CSR0L_SETUPEND_CLR); 420184610Salfred /* get latest status */ 421184610Salfred csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL); 422184610Salfred /* update EP0 state */ 423184610Salfred sc->sc_ep0_busy = 0; 424184610Salfred } 425184610Salfred if (sc->sc_ep0_busy) { 426252912Sgonzo DPRINTFN(0, "EP0 BUSY\n"); 427184610Salfred goto not_complete; 428184610Salfred } 429184610Salfred if (!(csr & MUSB2_MASK_CSR0L_RXPKTRDY)) { 430184610Salfred goto not_complete; 431184610Salfred } 432190721Sthompsa /* clear did stall flag */ 433190721Sthompsa td->did_stall = 0; 434184610Salfred /* get the packet byte count */ 435184610Salfred count = MUSB2_READ_2(sc, MUSB2_REG_RXCOUNT); 436184610Salfred 437184610Salfred /* verify data length */ 438184610Salfred if (count != td->remainder) { 439184610Salfred DPRINTFN(0, "Invalid SETUP packet " 440184610Salfred "length, %d bytes\n", count); 441190722Sthompsa MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 442190722Sthompsa MUSB2_MASK_CSR0L_RXPKTRDY_CLR); 443184610Salfred goto not_complete; 444184610Salfred } 445184610Salfred if (count != sizeof(req)) { 446184610Salfred DPRINTFN(0, "Unsupported SETUP packet " 447184610Salfred "length, %d bytes\n", count); 448190722Sthompsa MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 449190722Sthompsa MUSB2_MASK_CSR0L_RXPKTRDY_CLR); 450184610Salfred goto not_complete; 451184610Salfred } 452184610Salfred /* receive data */ 453184610Salfred bus_space_read_multi_1(sc->sc_io_tag, sc->sc_io_hdl, 454184610Salfred MUSB2_REG_EPFIFO(0), (void *)&req, sizeof(req)); 455184610Salfred 456184610Salfred /* copy data into real buffer */ 457194228Sthompsa usbd_copy_in(td->pc, 0, &req, sizeof(req)); 458184610Salfred 459184610Salfred td->offset = sizeof(req); 460184610Salfred td->remainder = 0; 461184610Salfred 462184610Salfred /* set pending command */ 463184610Salfred sc->sc_ep0_cmd = MUSB2_MASK_CSR0L_RXPKTRDY_CLR; 464184610Salfred 465184610Salfred /* we need set stall or dataend after this */ 466184610Salfred sc->sc_ep0_busy = 1; 467184610Salfred 468184610Salfred /* sneak peek the set address */ 469184610Salfred if ((req.bmRequestType == UT_WRITE_DEVICE) && 470184610Salfred (req.bRequest == UR_SET_ADDRESS)) { 471184610Salfred sc->sc_dv_addr = req.wValue[0] & 0x7F; 472184610Salfred } else { 473184610Salfred sc->sc_dv_addr = 0xFF; 474184610Salfred } 475252912Sgonzo 476252912Sgonzo musbotg_channel_free(sc, td); 477184610Salfred return (0); /* complete */ 478184610Salfred 479184610Salfrednot_complete: 480190721Sthompsa /* abort any ongoing transfer */ 481190721Sthompsa if (!td->did_stall) { 482190721Sthompsa DPRINTFN(4, "stalling\n"); 483190721Sthompsa MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 484190721Sthompsa MUSB2_MASK_CSR0L_SENDSTALL); 485190721Sthompsa td->did_stall = 1; 486190721Sthompsa } 487184610Salfred return (1); /* not complete */ 488184610Salfred} 489184610Salfred 490252912Sgonzostatic uint8_t 491252912Sgonzomusbotg_host_ctrl_setup_tx(struct musbotg_td *td) 492252912Sgonzo{ 493252912Sgonzo struct musbotg_softc *sc; 494252912Sgonzo struct usb_device_request req; 495252912Sgonzo uint8_t csr, csrh; 496252912Sgonzo 497252912Sgonzo /* get pointer to softc */ 498252912Sgonzo sc = MUSBOTG_PC2SC(td->pc); 499252912Sgonzo 500252912Sgonzo if (td->channel == -1) 501252912Sgonzo td->channel = musbotg_channel_alloc(sc, td); 502252912Sgonzo 503252912Sgonzo /* EP0 is busy, wait */ 504252912Sgonzo if (td->channel == -1) 505252912Sgonzo return (1); 506252912Sgonzo 507252912Sgonzo DPRINTFN(1, "ep_no=%d\n", td->channel); 508252912Sgonzo 509252912Sgonzo /* select endpoint 0 */ 510252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_EPINDEX, 0); 511252912Sgonzo 512252912Sgonzo /* read out FIFO status */ 513252912Sgonzo csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL); 514252912Sgonzo DPRINTFN(4, "csr=0x%02x\n", csr); 515252912Sgonzo 516252912Sgonzo /* Not ready yet yet */ 517252912Sgonzo if (csr & MUSB2_MASK_CSR0L_TXPKTRDY) 518252912Sgonzo return (1); 519252912Sgonzo 520252912Sgonzo /* Failed */ 521252912Sgonzo if (csr & (MUSB2_MASK_CSR0L_RXSTALL | 522252912Sgonzo MUSB2_MASK_CSR0L_ERROR)) 523252912Sgonzo { 524252912Sgonzo /* Clear status bit */ 525252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 0); 526252912Sgonzo DPRINTFN(1, "error bit set, csr=0x%02x\n", csr); 527252912Sgonzo td->error = 1; 528252912Sgonzo } 529252912Sgonzo 530252912Sgonzo if (csr & MUSB2_MASK_CSR0L_NAKTIMO) { 531252912Sgonzo DPRINTFN(1, "NAK timeout\n"); 532252912Sgonzo 533252912Sgonzo if (csr & MUSB2_MASK_CSR0L_TXFIFONEMPTY) { 534252912Sgonzo csrh = MUSB2_READ_1(sc, MUSB2_REG_TXCSRH); 535252912Sgonzo csrh |= MUSB2_MASK_CSR0H_FFLUSH; 536252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRH, csrh); 537252912Sgonzo csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL); 538252912Sgonzo if (csr & MUSB2_MASK_CSR0L_TXFIFONEMPTY) { 539252912Sgonzo csrh = MUSB2_READ_1(sc, MUSB2_REG_TXCSRH); 540252912Sgonzo csrh |= MUSB2_MASK_CSR0H_FFLUSH; 541252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRH, csrh); 542252912Sgonzo csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL); 543252912Sgonzo } 544252912Sgonzo } 545252912Sgonzo 546252912Sgonzo csr &= ~MUSB2_MASK_CSR0L_NAKTIMO; 547252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, csr); 548252912Sgonzo 549252912Sgonzo td->error = 1; 550252912Sgonzo } 551252912Sgonzo 552252912Sgonzo if (td->error) { 553252912Sgonzo musbotg_channel_free(sc, td); 554252912Sgonzo return (0); 555252912Sgonzo } 556252912Sgonzo 557252912Sgonzo /* Fifo is not empty and there is no NAK timeout */ 558252912Sgonzo if (csr & MUSB2_MASK_CSR0L_TXPKTRDY) 559252912Sgonzo return (1); 560252912Sgonzo 561252912Sgonzo /* check if we are complete */ 562252912Sgonzo if (td->remainder == 0) { 563252912Sgonzo /* we are complete */ 564252912Sgonzo musbotg_channel_free(sc, td); 565252912Sgonzo return (0); 566252912Sgonzo } 567252912Sgonzo 568252912Sgonzo /* copy data into real buffer */ 569252912Sgonzo usbd_copy_out(td->pc, 0, &req, sizeof(req)); 570252912Sgonzo 571252912Sgonzo /* send data */ 572252912Sgonzo bus_space_write_multi_1(sc->sc_io_tag, sc->sc_io_hdl, 573252912Sgonzo MUSB2_REG_EPFIFO(0), (void *)&req, sizeof(req)); 574252912Sgonzo 575252912Sgonzo /* update offset and remainder */ 576252912Sgonzo td->offset += sizeof(req); 577252912Sgonzo td->remainder -= sizeof(req); 578252912Sgonzo 579252912Sgonzo 580252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_TXNAKLIMIT, MAX_NAK_TO); 581252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_TXFADDR(0), td->dev_addr); 582252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_TXHADDR(0), td->haddr); 583252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_TXHUBPORT(0), td->hport); 584252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_TXTI, td->transfer_type); 585252912Sgonzo 586252912Sgonzo /* write command */ 587252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 588252912Sgonzo MUSB2_MASK_CSR0L_TXPKTRDY | 589252912Sgonzo MUSB2_MASK_CSR0L_SETUPPKT); 590252912Sgonzo 591252912Sgonzo /* Just to be consistent, not used above */ 592252912Sgonzo td->transaction_started = 1; 593252912Sgonzo 594252912Sgonzo return (1); /* in progress */ 595252912Sgonzo} 596252912Sgonzo 597184610Salfred/* Control endpoint only data handling functions (RX/TX/SYNC) */ 598184610Salfred 599184610Salfredstatic uint8_t 600252912Sgonzomusbotg_dev_ctrl_data_rx(struct musbotg_td *td) 601184610Salfred{ 602192984Sthompsa struct usb_page_search buf_res; 603184610Salfred struct musbotg_softc *sc; 604184610Salfred uint16_t count; 605184610Salfred uint8_t csr; 606184610Salfred uint8_t got_short; 607184610Salfred 608184610Salfred /* get pointer to softc */ 609184610Salfred sc = MUSBOTG_PC2SC(td->pc); 610184610Salfred 611184610Salfred /* select endpoint 0 */ 612184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_EPINDEX, 0); 613184610Salfred 614184610Salfred /* check if a command is pending */ 615184610Salfred if (sc->sc_ep0_cmd) { 616184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, sc->sc_ep0_cmd); 617184610Salfred sc->sc_ep0_cmd = 0; 618184610Salfred } 619184610Salfred /* read out FIFO status */ 620184610Salfred csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL); 621184610Salfred 622184610Salfred DPRINTFN(4, "csr=0x%02x\n", csr); 623184610Salfred 624184610Salfred got_short = 0; 625184610Salfred 626184610Salfred if (csr & (MUSB2_MASK_CSR0L_SETUPEND | 627184610Salfred MUSB2_MASK_CSR0L_SENTSTALL)) { 628184610Salfred if (td->remainder == 0) { 629184610Salfred /* 630184610Salfred * We are actually complete and have 631184610Salfred * received the next SETUP 632184610Salfred */ 633184610Salfred DPRINTFN(4, "faking complete\n"); 634184610Salfred return (0); /* complete */ 635184610Salfred } 636184610Salfred /* 637184610Salfred * USB Host Aborted the transfer. 638184610Salfred */ 639184610Salfred td->error = 1; 640184610Salfred return (0); /* complete */ 641184610Salfred } 642184610Salfred if (!(csr & MUSB2_MASK_CSR0L_RXPKTRDY)) { 643184610Salfred return (1); /* not complete */ 644184610Salfred } 645184610Salfred /* get the packet byte count */ 646184610Salfred count = MUSB2_READ_2(sc, MUSB2_REG_RXCOUNT); 647184610Salfred 648184610Salfred /* verify the packet byte count */ 649184610Salfred if (count != td->max_frame_size) { 650184610Salfred if (count < td->max_frame_size) { 651184610Salfred /* we have a short packet */ 652184610Salfred td->short_pkt = 1; 653184610Salfred got_short = 1; 654184610Salfred } else { 655184610Salfred /* invalid USB packet */ 656184610Salfred td->error = 1; 657184610Salfred return (0); /* we are complete */ 658184610Salfred } 659184610Salfred } 660184610Salfred /* verify the packet byte count */ 661184610Salfred if (count > td->remainder) { 662184610Salfred /* invalid USB packet */ 663184610Salfred td->error = 1; 664184610Salfred return (0); /* we are complete */ 665184610Salfred } 666184610Salfred while (count > 0) { 667184610Salfred uint32_t temp; 668184610Salfred 669194228Sthompsa usbd_get_page(td->pc, td->offset, &buf_res); 670184610Salfred 671184610Salfred /* get correct length */ 672184610Salfred if (buf_res.length > count) { 673184610Salfred buf_res.length = count; 674184610Salfred } 675184610Salfred /* check for unaligned memory address */ 676184610Salfred if (USB_P2U(buf_res.buffer) & 3) { 677184610Salfred 678184610Salfred temp = count & ~3; 679184610Salfred 680184610Salfred if (temp) { 681184610Salfred /* receive data 4 bytes at a time */ 682184610Salfred bus_space_read_multi_4(sc->sc_io_tag, sc->sc_io_hdl, 683184610Salfred MUSB2_REG_EPFIFO(0), sc->sc_bounce_buf, 684184610Salfred temp / 4); 685184610Salfred } 686184610Salfred temp = count & 3; 687184610Salfred if (temp) { 688184610Salfred /* receive data 1 byte at a time */ 689184610Salfred bus_space_read_multi_1(sc->sc_io_tag, sc->sc_io_hdl, 690184610Salfred MUSB2_REG_EPFIFO(0), 691184610Salfred (void *)(&sc->sc_bounce_buf[count / 4]), temp); 692184610Salfred } 693194228Sthompsa usbd_copy_in(td->pc, td->offset, 694184610Salfred sc->sc_bounce_buf, count); 695184610Salfred 696184610Salfred /* update offset and remainder */ 697184610Salfred td->offset += count; 698184610Salfred td->remainder -= count; 699184610Salfred break; 700184610Salfred } 701184610Salfred /* check if we can optimise */ 702184610Salfred if (buf_res.length >= 4) { 703184610Salfred 704184610Salfred /* receive data 4 bytes at a time */ 705184610Salfred bus_space_read_multi_4(sc->sc_io_tag, sc->sc_io_hdl, 706184610Salfred MUSB2_REG_EPFIFO(0), buf_res.buffer, 707184610Salfred buf_res.length / 4); 708184610Salfred 709184610Salfred temp = buf_res.length & ~3; 710184610Salfred 711184610Salfred /* update counters */ 712184610Salfred count -= temp; 713184610Salfred td->offset += temp; 714184610Salfred td->remainder -= temp; 715184610Salfred continue; 716184610Salfred } 717184610Salfred /* receive data */ 718184610Salfred bus_space_read_multi_1(sc->sc_io_tag, sc->sc_io_hdl, 719184610Salfred MUSB2_REG_EPFIFO(0), buf_res.buffer, buf_res.length); 720184610Salfred 721184610Salfred /* update counters */ 722184610Salfred count -= buf_res.length; 723184610Salfred td->offset += buf_res.length; 724184610Salfred td->remainder -= buf_res.length; 725184610Salfred } 726184610Salfred 727184610Salfred /* check if we are complete */ 728184610Salfred if ((td->remainder == 0) || got_short) { 729184610Salfred if (td->short_pkt) { 730184610Salfred /* we are complete */ 731184610Salfred sc->sc_ep0_cmd = MUSB2_MASK_CSR0L_RXPKTRDY_CLR; 732184610Salfred return (0); 733184610Salfred } 734184610Salfred /* else need to receive a zero length packet */ 735184610Salfred } 736184610Salfred /* write command - need more data */ 737184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 738184610Salfred MUSB2_MASK_CSR0L_RXPKTRDY_CLR); 739184610Salfred return (1); /* not complete */ 740184610Salfred} 741184610Salfred 742184610Salfredstatic uint8_t 743252912Sgonzomusbotg_dev_ctrl_data_tx(struct musbotg_td *td) 744184610Salfred{ 745192984Sthompsa struct usb_page_search buf_res; 746184610Salfred struct musbotg_softc *sc; 747184610Salfred uint16_t count; 748184610Salfred uint8_t csr; 749184610Salfred 750184610Salfred /* get pointer to softc */ 751184610Salfred sc = MUSBOTG_PC2SC(td->pc); 752184610Salfred 753184610Salfred /* select endpoint 0 */ 754184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_EPINDEX, 0); 755184610Salfred 756184610Salfred /* check if a command is pending */ 757184610Salfred if (sc->sc_ep0_cmd) { 758184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, sc->sc_ep0_cmd); 759184610Salfred sc->sc_ep0_cmd = 0; 760184610Salfred } 761184610Salfred /* read out FIFO status */ 762184610Salfred csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL); 763184610Salfred 764184610Salfred DPRINTFN(4, "csr=0x%02x\n", csr); 765184610Salfred 766184610Salfred if (csr & (MUSB2_MASK_CSR0L_SETUPEND | 767184610Salfred MUSB2_MASK_CSR0L_SENTSTALL)) { 768184610Salfred /* 769184610Salfred * The current transfer was aborted 770184610Salfred * by the USB Host 771184610Salfred */ 772184610Salfred td->error = 1; 773184610Salfred return (0); /* complete */ 774184610Salfred } 775184610Salfred if (csr & MUSB2_MASK_CSR0L_TXPKTRDY) { 776184610Salfred return (1); /* not complete */ 777184610Salfred } 778184610Salfred count = td->max_frame_size; 779184610Salfred if (td->remainder < count) { 780184610Salfred /* we have a short packet */ 781184610Salfred td->short_pkt = 1; 782184610Salfred count = td->remainder; 783184610Salfred } 784184610Salfred while (count > 0) { 785184610Salfred uint32_t temp; 786184610Salfred 787194228Sthompsa usbd_get_page(td->pc, td->offset, &buf_res); 788184610Salfred 789184610Salfred /* get correct length */ 790184610Salfred if (buf_res.length > count) { 791184610Salfred buf_res.length = count; 792184610Salfred } 793184610Salfred /* check for unaligned memory address */ 794184610Salfred if (USB_P2U(buf_res.buffer) & 3) { 795184610Salfred 796194228Sthompsa usbd_copy_out(td->pc, td->offset, 797184610Salfred sc->sc_bounce_buf, count); 798184610Salfred 799184610Salfred temp = count & ~3; 800184610Salfred 801184610Salfred if (temp) { 802184610Salfred /* transmit data 4 bytes at a time */ 803184610Salfred bus_space_write_multi_4(sc->sc_io_tag, sc->sc_io_hdl, 804184610Salfred MUSB2_REG_EPFIFO(0), sc->sc_bounce_buf, 805184610Salfred temp / 4); 806184610Salfred } 807184610Salfred temp = count & 3; 808184610Salfred if (temp) { 809184610Salfred /* receive data 1 byte at a time */ 810184610Salfred bus_space_write_multi_1(sc->sc_io_tag, sc->sc_io_hdl, 811184610Salfred MUSB2_REG_EPFIFO(0), 812184610Salfred ((void *)&sc->sc_bounce_buf[count / 4]), temp); 813184610Salfred } 814184610Salfred /* update offset and remainder */ 815184610Salfred td->offset += count; 816184610Salfred td->remainder -= count; 817184610Salfred break; 818184610Salfred } 819184610Salfred /* check if we can optimise */ 820184610Salfred if (buf_res.length >= 4) { 821184610Salfred 822184610Salfred /* transmit data 4 bytes at a time */ 823184610Salfred bus_space_write_multi_4(sc->sc_io_tag, sc->sc_io_hdl, 824184610Salfred MUSB2_REG_EPFIFO(0), buf_res.buffer, 825184610Salfred buf_res.length / 4); 826184610Salfred 827184610Salfred temp = buf_res.length & ~3; 828184610Salfred 829184610Salfred /* update counters */ 830184610Salfred count -= temp; 831184610Salfred td->offset += temp; 832184610Salfred td->remainder -= temp; 833184610Salfred continue; 834184610Salfred } 835184610Salfred /* transmit data */ 836184610Salfred bus_space_write_multi_1(sc->sc_io_tag, sc->sc_io_hdl, 837184610Salfred MUSB2_REG_EPFIFO(0), buf_res.buffer, buf_res.length); 838184610Salfred 839184610Salfred /* update counters */ 840184610Salfred count -= buf_res.length; 841184610Salfred td->offset += buf_res.length; 842184610Salfred td->remainder -= buf_res.length; 843184610Salfred } 844184610Salfred 845184610Salfred /* check remainder */ 846184610Salfred if (td->remainder == 0) { 847184610Salfred if (td->short_pkt) { 848184610Salfred sc->sc_ep0_cmd = MUSB2_MASK_CSR0L_TXPKTRDY; 849184610Salfred return (0); /* complete */ 850184610Salfred } 851184610Salfred /* else we need to transmit a short packet */ 852184610Salfred } 853184610Salfred /* write command */ 854184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 855184610Salfred MUSB2_MASK_CSR0L_TXPKTRDY); 856184610Salfred 857184610Salfred return (1); /* not complete */ 858184610Salfred} 859184610Salfred 860184610Salfredstatic uint8_t 861252912Sgonzomusbotg_host_ctrl_data_rx(struct musbotg_td *td) 862184610Salfred{ 863252912Sgonzo struct usb_page_search buf_res; 864184610Salfred struct musbotg_softc *sc; 865252912Sgonzo uint16_t count; 866184610Salfred uint8_t csr; 867252912Sgonzo uint8_t got_short; 868184610Salfred 869184610Salfred /* get pointer to softc */ 870184610Salfred sc = MUSBOTG_PC2SC(td->pc); 871184610Salfred 872252912Sgonzo if (td->channel == -1) 873252912Sgonzo td->channel = musbotg_channel_alloc(sc, td); 874252912Sgonzo 875252912Sgonzo /* EP0 is busy, wait */ 876252912Sgonzo if (td->channel == -1) 877252912Sgonzo return (1); 878252912Sgonzo 879252912Sgonzo DPRINTFN(1, "ep_no=%d\n", td->channel); 880252912Sgonzo 881184610Salfred /* select endpoint 0 */ 882184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_EPINDEX, 0); 883184610Salfred 884252912Sgonzo /* read out FIFO status */ 885252912Sgonzo csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL); 886252912Sgonzo 887252912Sgonzo DPRINTFN(4, "csr=0x%02x\n", csr); 888252912Sgonzo 889252912Sgonzo got_short = 0; 890252912Sgonzo if (!td->transaction_started) { 891252912Sgonzo td->transaction_started = 1; 892252912Sgonzo 893252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_RXNAKLIMIT, MAX_NAK_TO); 894252912Sgonzo 895252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_RXFADDR(0), 896252912Sgonzo td->dev_addr); 897252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_RXHADDR(0), td->haddr); 898252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_RXHUBPORT(0), td->hport); 899252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_RXTI, td->transfer_type); 900252912Sgonzo 901252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 902252912Sgonzo MUSB2_MASK_CSR0L_REQPKT); 903252912Sgonzo 904252912Sgonzo return (1); 905252912Sgonzo } 906252912Sgonzo 907252912Sgonzo if (csr & MUSB2_MASK_CSR0L_NAKTIMO) { 908252912Sgonzo csr &= ~MUSB2_MASK_CSR0L_REQPKT; 909252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, csr); 910252912Sgonzo 911252912Sgonzo csr &= ~MUSB2_MASK_CSR0L_NAKTIMO; 912252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, csr); 913252912Sgonzo 914252912Sgonzo td->error = 1; 915252912Sgonzo } 916252912Sgonzo 917252912Sgonzo /* Failed */ 918252912Sgonzo if (csr & (MUSB2_MASK_CSR0L_RXSTALL | 919252912Sgonzo MUSB2_MASK_CSR0L_ERROR)) 920252912Sgonzo { 921252912Sgonzo /* Clear status bit */ 922252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 0); 923252912Sgonzo DPRINTFN(1, "error bit set, csr=0x%02x\n", csr); 924252912Sgonzo td->error = 1; 925252912Sgonzo } 926252912Sgonzo 927252912Sgonzo if (td->error) { 928252912Sgonzo musbotg_channel_free(sc, td); 929252912Sgonzo return (0); /* we are complete */ 930252912Sgonzo } 931252912Sgonzo 932252912Sgonzo if (!(csr & MUSB2_MASK_CSR0L_RXPKTRDY)) 933252912Sgonzo return (1); /* not yet */ 934252912Sgonzo 935252912Sgonzo /* get the packet byte count */ 936252912Sgonzo count = MUSB2_READ_2(sc, MUSB2_REG_RXCOUNT); 937252912Sgonzo 938252912Sgonzo /* verify the packet byte count */ 939252912Sgonzo if (count != td->max_frame_size) { 940252912Sgonzo if (count < td->max_frame_size) { 941252912Sgonzo /* we have a short packet */ 942252912Sgonzo td->short_pkt = 1; 943252912Sgonzo got_short = 1; 944252912Sgonzo } else { 945252912Sgonzo /* invalid USB packet */ 946252912Sgonzo td->error = 1; 947252912Sgonzo musbotg_channel_free(sc, td); 948252912Sgonzo return (0); /* we are complete */ 949252912Sgonzo } 950252912Sgonzo } 951252912Sgonzo /* verify the packet byte count */ 952252912Sgonzo if (count > td->remainder) { 953252912Sgonzo /* invalid USB packet */ 954252912Sgonzo td->error = 1; 955252912Sgonzo musbotg_channel_free(sc, td); 956252912Sgonzo return (0); /* we are complete */ 957252912Sgonzo } 958252912Sgonzo while (count > 0) { 959252912Sgonzo uint32_t temp; 960252912Sgonzo 961252912Sgonzo usbd_get_page(td->pc, td->offset, &buf_res); 962252912Sgonzo 963252912Sgonzo /* get correct length */ 964252912Sgonzo if (buf_res.length > count) { 965252912Sgonzo buf_res.length = count; 966252912Sgonzo } 967252912Sgonzo /* check for unaligned memory address */ 968252912Sgonzo if (USB_P2U(buf_res.buffer) & 3) { 969252912Sgonzo 970252912Sgonzo temp = count & ~3; 971252912Sgonzo 972252912Sgonzo if (temp) { 973252912Sgonzo /* receive data 4 bytes at a time */ 974252912Sgonzo bus_space_read_multi_4(sc->sc_io_tag, sc->sc_io_hdl, 975252912Sgonzo MUSB2_REG_EPFIFO(0), sc->sc_bounce_buf, 976252912Sgonzo temp / 4); 977252912Sgonzo } 978252912Sgonzo temp = count & 3; 979252912Sgonzo if (temp) { 980252912Sgonzo /* receive data 1 byte at a time */ 981252912Sgonzo bus_space_read_multi_1(sc->sc_io_tag, sc->sc_io_hdl, 982252912Sgonzo MUSB2_REG_EPFIFO(0), 983252912Sgonzo (void *)(&sc->sc_bounce_buf[count / 4]), temp); 984252912Sgonzo } 985252912Sgonzo usbd_copy_in(td->pc, td->offset, 986252912Sgonzo sc->sc_bounce_buf, count); 987252912Sgonzo 988252912Sgonzo /* update offset and remainder */ 989252912Sgonzo td->offset += count; 990252912Sgonzo td->remainder -= count; 991252912Sgonzo break; 992252912Sgonzo } 993252912Sgonzo /* check if we can optimise */ 994252912Sgonzo if (buf_res.length >= 4) { 995252912Sgonzo 996252912Sgonzo /* receive data 4 bytes at a time */ 997252912Sgonzo bus_space_read_multi_4(sc->sc_io_tag, sc->sc_io_hdl, 998252912Sgonzo MUSB2_REG_EPFIFO(0), buf_res.buffer, 999252912Sgonzo buf_res.length / 4); 1000252912Sgonzo 1001252912Sgonzo temp = buf_res.length & ~3; 1002252912Sgonzo 1003252912Sgonzo /* update counters */ 1004252912Sgonzo count -= temp; 1005252912Sgonzo td->offset += temp; 1006252912Sgonzo td->remainder -= temp; 1007252912Sgonzo continue; 1008252912Sgonzo } 1009252912Sgonzo /* receive data */ 1010252912Sgonzo bus_space_read_multi_1(sc->sc_io_tag, sc->sc_io_hdl, 1011252912Sgonzo MUSB2_REG_EPFIFO(0), buf_res.buffer, buf_res.length); 1012252912Sgonzo 1013252912Sgonzo /* update counters */ 1014252912Sgonzo count -= buf_res.length; 1015252912Sgonzo td->offset += buf_res.length; 1016252912Sgonzo td->remainder -= buf_res.length; 1017252912Sgonzo } 1018252912Sgonzo 1019252912Sgonzo csr &= ~MUSB2_MASK_CSR0L_RXPKTRDY; 1020252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, csr); 1021252912Sgonzo 1022252912Sgonzo /* check if we are complete */ 1023252912Sgonzo if ((td->remainder == 0) || got_short) { 1024252912Sgonzo if (td->short_pkt) { 1025252912Sgonzo /* we are complete */ 1026252912Sgonzo 1027252912Sgonzo musbotg_channel_free(sc, td); 1028252912Sgonzo return (0); 1029252912Sgonzo } 1030252912Sgonzo /* else need to receive a zero length packet */ 1031252912Sgonzo } 1032252912Sgonzo 1033252912Sgonzo td->transaction_started = 1; 1034252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 1035252912Sgonzo MUSB2_MASK_CSR0L_REQPKT); 1036252912Sgonzo 1037252912Sgonzo return (1); /* not complete */ 1038252912Sgonzo} 1039252912Sgonzo 1040252912Sgonzostatic uint8_t 1041252912Sgonzomusbotg_host_ctrl_data_tx(struct musbotg_td *td) 1042252912Sgonzo{ 1043252912Sgonzo struct usb_page_search buf_res; 1044252912Sgonzo struct musbotg_softc *sc; 1045252912Sgonzo uint16_t count; 1046252912Sgonzo uint8_t csr, csrh; 1047252912Sgonzo 1048252912Sgonzo /* get pointer to softc */ 1049252912Sgonzo sc = MUSBOTG_PC2SC(td->pc); 1050252912Sgonzo 1051252912Sgonzo if (td->channel == -1) 1052252912Sgonzo td->channel = musbotg_channel_alloc(sc, td); 1053252912Sgonzo 1054252912Sgonzo /* No free EPs */ 1055252912Sgonzo if (td->channel == -1) 1056252912Sgonzo return (1); 1057252912Sgonzo 1058252912Sgonzo DPRINTFN(1, "ep_no=%d\n", td->channel); 1059252912Sgonzo 1060252912Sgonzo /* select endpoint */ 1061252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_EPINDEX, 0); 1062252912Sgonzo 1063252912Sgonzo /* read out FIFO status */ 1064252912Sgonzo csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL); 1065252912Sgonzo DPRINTFN(4, "csr=0x%02x\n", csr); 1066252912Sgonzo 1067252912Sgonzo if (csr & (MUSB2_MASK_CSR0L_RXSTALL | 1068252912Sgonzo MUSB2_MASK_CSR0L_ERROR)) { 1069252912Sgonzo /* clear status bits */ 1070252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 0); 1071252912Sgonzo td->error = 1; 1072252912Sgonzo } 1073252912Sgonzo 1074252912Sgonzo if (csr & MUSB2_MASK_CSR0L_NAKTIMO ) { 1075252912Sgonzo 1076252912Sgonzo if (csr & MUSB2_MASK_CSR0L_TXFIFONEMPTY) { 1077252912Sgonzo csrh = MUSB2_READ_1(sc, MUSB2_REG_TXCSRH); 1078252912Sgonzo csrh |= MUSB2_MASK_CSR0H_FFLUSH; 1079252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRH, csrh); 1080252912Sgonzo csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL); 1081252912Sgonzo if (csr & MUSB2_MASK_CSR0L_TXFIFONEMPTY) { 1082252912Sgonzo csrh = MUSB2_READ_1(sc, MUSB2_REG_TXCSRH); 1083252912Sgonzo csrh |= MUSB2_MASK_CSR0H_FFLUSH; 1084252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRH, csrh); 1085252912Sgonzo csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL); 1086252912Sgonzo } 1087252912Sgonzo } 1088252912Sgonzo 1089252912Sgonzo csr &= ~MUSB2_MASK_CSR0L_NAKTIMO; 1090252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, csr); 1091252912Sgonzo 1092252912Sgonzo td->error = 1; 1093252912Sgonzo } 1094252912Sgonzo 1095252912Sgonzo 1096252912Sgonzo if (td->error) { 1097252912Sgonzo musbotg_channel_free(sc, td); 1098252912Sgonzo return (0); /* complete */ 1099252912Sgonzo } 1100252912Sgonzo 1101252912Sgonzo /* 1102252912Sgonzo * Wait while FIFO is empty. 1103252912Sgonzo * Do not flush it because it will cause transactions 1104252912Sgonzo * with size more then packet size. It might upset 1105252912Sgonzo * some devices 1106252912Sgonzo */ 1107252912Sgonzo if (csr & MUSB2_MASK_CSR0L_TXFIFONEMPTY) 1108252912Sgonzo return (1); 1109252912Sgonzo 1110252912Sgonzo /* Packet still being processed */ 1111252912Sgonzo if (csr & MUSB2_MASK_CSR0L_TXPKTRDY) 1112252912Sgonzo return (1); 1113252912Sgonzo 1114252912Sgonzo if (td->transaction_started) { 1115252912Sgonzo /* check remainder */ 1116252912Sgonzo if (td->remainder == 0) { 1117252912Sgonzo if (td->short_pkt) { 1118252912Sgonzo musbotg_channel_free(sc, td); 1119252912Sgonzo return (0); /* complete */ 1120252912Sgonzo } 1121252912Sgonzo /* else we need to transmit a short packet */ 1122252912Sgonzo } 1123252912Sgonzo 1124252912Sgonzo /* We're not complete - more transactions required */ 1125252912Sgonzo td->transaction_started = 0; 1126252912Sgonzo } 1127252912Sgonzo 1128252912Sgonzo /* check for short packet */ 1129252912Sgonzo count = td->max_frame_size; 1130252912Sgonzo if (td->remainder < count) { 1131252912Sgonzo /* we have a short packet */ 1132252912Sgonzo td->short_pkt = 1; 1133252912Sgonzo count = td->remainder; 1134252912Sgonzo } 1135252912Sgonzo 1136252912Sgonzo while (count > 0) { 1137252912Sgonzo uint32_t temp; 1138252912Sgonzo 1139252912Sgonzo usbd_get_page(td->pc, td->offset, &buf_res); 1140252912Sgonzo 1141252912Sgonzo /* get correct length */ 1142252912Sgonzo if (buf_res.length > count) { 1143252912Sgonzo buf_res.length = count; 1144252912Sgonzo } 1145252912Sgonzo /* check for unaligned memory address */ 1146252912Sgonzo if (USB_P2U(buf_res.buffer) & 3) { 1147252912Sgonzo 1148252912Sgonzo usbd_copy_out(td->pc, td->offset, 1149252912Sgonzo sc->sc_bounce_buf, count); 1150252912Sgonzo 1151252912Sgonzo temp = count & ~3; 1152252912Sgonzo 1153252912Sgonzo if (temp) { 1154252912Sgonzo /* transmit data 4 bytes at a time */ 1155252912Sgonzo bus_space_write_multi_4(sc->sc_io_tag, 1156252912Sgonzo sc->sc_io_hdl, MUSB2_REG_EPFIFO(0), 1157252912Sgonzo sc->sc_bounce_buf, temp / 4); 1158252912Sgonzo } 1159252912Sgonzo temp = count & 3; 1160252912Sgonzo if (temp) { 1161252912Sgonzo /* receive data 1 byte at a time */ 1162252912Sgonzo bus_space_write_multi_1(sc->sc_io_tag, sc->sc_io_hdl, 1163252912Sgonzo MUSB2_REG_EPFIFO(0), 1164252912Sgonzo ((void *)&sc->sc_bounce_buf[count / 4]), temp); 1165252912Sgonzo } 1166252912Sgonzo /* update offset and remainder */ 1167252912Sgonzo td->offset += count; 1168252912Sgonzo td->remainder -= count; 1169252912Sgonzo break; 1170252912Sgonzo } 1171252912Sgonzo /* check if we can optimise */ 1172252912Sgonzo if (buf_res.length >= 4) { 1173252912Sgonzo 1174252912Sgonzo /* transmit data 4 bytes at a time */ 1175252912Sgonzo bus_space_write_multi_4(sc->sc_io_tag, sc->sc_io_hdl, 1176252912Sgonzo MUSB2_REG_EPFIFO(0), buf_res.buffer, 1177252912Sgonzo buf_res.length / 4); 1178252912Sgonzo 1179252912Sgonzo temp = buf_res.length & ~3; 1180252912Sgonzo 1181252912Sgonzo /* update counters */ 1182252912Sgonzo count -= temp; 1183252912Sgonzo td->offset += temp; 1184252912Sgonzo td->remainder -= temp; 1185252912Sgonzo continue; 1186252912Sgonzo } 1187252912Sgonzo /* transmit data */ 1188252912Sgonzo bus_space_write_multi_1(sc->sc_io_tag, sc->sc_io_hdl, 1189252912Sgonzo MUSB2_REG_EPFIFO(0), buf_res.buffer, 1190252912Sgonzo buf_res.length); 1191252912Sgonzo 1192252912Sgonzo /* update counters */ 1193252912Sgonzo count -= buf_res.length; 1194252912Sgonzo td->offset += buf_res.length; 1195252912Sgonzo td->remainder -= buf_res.length; 1196252912Sgonzo } 1197252912Sgonzo 1198252912Sgonzo /* Function address */ 1199252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_TXFADDR(0), td->dev_addr); 1200252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_TXHADDR(0), td->haddr); 1201252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_TXHUBPORT(0), td->hport); 1202252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_TXTI, td->transfer_type); 1203252912Sgonzo 1204252912Sgonzo /* TX NAK timeout */ 1205252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_TXNAKLIMIT, MAX_NAK_TO); 1206252912Sgonzo 1207252912Sgonzo /* write command */ 1208252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 1209252912Sgonzo MUSB2_MASK_CSR0L_TXPKTRDY); 1210252912Sgonzo 1211252912Sgonzo td->transaction_started = 1; 1212252912Sgonzo 1213252912Sgonzo return (1); /* not complete */ 1214252912Sgonzo} 1215252912Sgonzo 1216252912Sgonzostatic uint8_t 1217252912Sgonzomusbotg_dev_ctrl_status(struct musbotg_td *td) 1218252912Sgonzo{ 1219252912Sgonzo struct musbotg_softc *sc; 1220252912Sgonzo uint8_t csr; 1221252912Sgonzo 1222252912Sgonzo /* get pointer to softc */ 1223252912Sgonzo sc = MUSBOTG_PC2SC(td->pc); 1224252912Sgonzo 1225252912Sgonzo /* select endpoint 0 */ 1226252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_EPINDEX, 0); 1227252912Sgonzo 1228184610Salfred if (sc->sc_ep0_busy) { 1229184610Salfred sc->sc_ep0_busy = 0; 1230184610Salfred sc->sc_ep0_cmd |= MUSB2_MASK_CSR0L_DATAEND; 1231184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, sc->sc_ep0_cmd); 1232184610Salfred sc->sc_ep0_cmd = 0; 1233184610Salfred } 1234184610Salfred /* read out FIFO status */ 1235184610Salfred csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL); 1236184610Salfred 1237184610Salfred DPRINTFN(4, "csr=0x%02x\n", csr); 1238184610Salfred 1239184610Salfred if (csr & MUSB2_MASK_CSR0L_DATAEND) { 1240184610Salfred /* wait for interrupt */ 1241184610Salfred return (1); /* not complete */ 1242184610Salfred } 1243184610Salfred if (sc->sc_dv_addr != 0xFF) { 1244184610Salfred /* write function address */ 1245184610Salfred musbotg_set_address(sc, sc->sc_dv_addr); 1246184610Salfred } 1247252912Sgonzo 1248252912Sgonzo musbotg_channel_free(sc, td); 1249184610Salfred return (0); /* complete */ 1250184610Salfred} 1251184610Salfred 1252184610Salfredstatic uint8_t 1253252912Sgonzomusbotg_host_ctrl_status_rx(struct musbotg_td *td) 1254184610Salfred{ 1255252912Sgonzo struct musbotg_softc *sc; 1256252912Sgonzo uint8_t csr, csrh; 1257252912Sgonzo 1258252912Sgonzo /* get pointer to softc */ 1259252912Sgonzo sc = MUSBOTG_PC2SC(td->pc); 1260252912Sgonzo 1261252912Sgonzo if (td->channel == -1) 1262252912Sgonzo td->channel = musbotg_channel_alloc(sc, td); 1263252912Sgonzo 1264252912Sgonzo /* EP0 is busy, wait */ 1265252912Sgonzo if (td->channel == -1) 1266252912Sgonzo return (1); 1267252912Sgonzo 1268252912Sgonzo DPRINTFN(1, "ep_no=%d\n", td->channel); 1269252912Sgonzo 1270252912Sgonzo /* select endpoint 0 */ 1271252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_EPINDEX, 0); 1272252912Sgonzo 1273252912Sgonzo if (!td->transaction_started) { 1274252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_RXFADDR(0), 1275252912Sgonzo td->dev_addr); 1276252912Sgonzo 1277252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_RXHADDR(0), td->haddr); 1278252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_RXHUBPORT(0), td->hport); 1279252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_RXTI, td->transfer_type); 1280252912Sgonzo 1281252912Sgonzo /* RX NAK timeout */ 1282252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_RXNAKLIMIT, MAX_NAK_TO); 1283252912Sgonzo 1284252912Sgonzo td->transaction_started = 1; 1285252912Sgonzo 1286252912Sgonzo /* Disable PING */ 1287252912Sgonzo csrh = MUSB2_READ_1(sc, MUSB2_REG_RXCSRH); 1288252912Sgonzo csrh |= MUSB2_MASK_CSR0H_PING_DIS; 1289252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_RXCSRH, csrh); 1290252912Sgonzo 1291252912Sgonzo /* write command */ 1292252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 1293252912Sgonzo MUSB2_MASK_CSR0L_STATUSPKT | 1294252912Sgonzo MUSB2_MASK_CSR0L_REQPKT); 1295252912Sgonzo 1296252912Sgonzo return (1); /* Just started */ 1297252912Sgonzo 1298252912Sgonzo } 1299252912Sgonzo 1300252912Sgonzo csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL); 1301252912Sgonzo 1302252912Sgonzo DPRINTFN(4, "IN STATUS csr=0x%02x\n", csr); 1303252912Sgonzo 1304252912Sgonzo if (csr & MUSB2_MASK_CSR0L_RXPKTRDY) { 1305252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 1306252912Sgonzo MUSB2_MASK_CSR0L_RXPKTRDY_CLR); 1307252912Sgonzo musbotg_channel_free(sc, td); 1308252912Sgonzo return (0); /* complete */ 1309252912Sgonzo } 1310252912Sgonzo 1311252912Sgonzo if (csr & MUSB2_MASK_CSR0L_NAKTIMO) { 1312252912Sgonzo csr &= ~ (MUSB2_MASK_CSR0L_STATUSPKT | 1313252912Sgonzo MUSB2_MASK_CSR0L_REQPKT); 1314252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, csr); 1315252912Sgonzo 1316252912Sgonzo csr &= ~MUSB2_MASK_CSR0L_NAKTIMO; 1317252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, csr); 1318252912Sgonzo td->error = 1; 1319252912Sgonzo } 1320252912Sgonzo 1321252912Sgonzo /* Failed */ 1322252912Sgonzo if (csr & (MUSB2_MASK_CSR0L_RXSTALL | 1323252912Sgonzo MUSB2_MASK_CSR0L_ERROR)) 1324252912Sgonzo { 1325252912Sgonzo /* Clear status bit */ 1326252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 0); 1327252912Sgonzo DPRINTFN(1, "error bit set, csr=0x%02x\n", csr); 1328252912Sgonzo td->error = 1; 1329252912Sgonzo } 1330252912Sgonzo 1331252912Sgonzo if (td->error) { 1332252912Sgonzo musbotg_channel_free(sc, td); 1333252912Sgonzo return (0); 1334252912Sgonzo } 1335252912Sgonzo 1336252912Sgonzo return (1); /* Not ready yet */ 1337252912Sgonzo} 1338252912Sgonzo 1339252912Sgonzostatic uint8_t 1340252912Sgonzomusbotg_host_ctrl_status_tx(struct musbotg_td *td) 1341252912Sgonzo{ 1342252912Sgonzo struct musbotg_softc *sc; 1343252912Sgonzo uint8_t csr; 1344252912Sgonzo 1345252912Sgonzo /* get pointer to softc */ 1346252912Sgonzo sc = MUSBOTG_PC2SC(td->pc); 1347252912Sgonzo 1348252912Sgonzo if (td->channel == -1) 1349252912Sgonzo td->channel = musbotg_channel_alloc(sc, td); 1350252912Sgonzo 1351252912Sgonzo /* EP0 is busy, wait */ 1352252912Sgonzo if (td->channel == -1) 1353252912Sgonzo return (1); 1354252912Sgonzo 1355252912Sgonzo DPRINTFN(1, "ep_no=%d/%d [%d@%d.%d/%02x]\n", td->channel, td->transaction_started, 1356252912Sgonzo td->dev_addr,td->haddr,td->hport, td->transfer_type); 1357252912Sgonzo 1358252912Sgonzo /* select endpoint 0 */ 1359252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_EPINDEX, 0); 1360252912Sgonzo 1361252912Sgonzo csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL); 1362252912Sgonzo DPRINTFN(4, "csr=0x%02x\n", csr); 1363252912Sgonzo 1364252912Sgonzo /* Not yet */ 1365252912Sgonzo if (csr & MUSB2_MASK_CSR0L_TXPKTRDY) 1366252912Sgonzo return (1); 1367252912Sgonzo 1368252912Sgonzo /* Failed */ 1369252912Sgonzo if (csr & (MUSB2_MASK_CSR0L_RXSTALL | 1370252912Sgonzo MUSB2_MASK_CSR0L_ERROR)) 1371252912Sgonzo { 1372252912Sgonzo /* Clear status bit */ 1373252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 0); 1374252912Sgonzo DPRINTFN(1, "error bit set, csr=0x%02x\n", csr); 1375252912Sgonzo td->error = 1; 1376252912Sgonzo musbotg_channel_free(sc, td); 1377252912Sgonzo return (0); /* complete */ 1378252912Sgonzo } 1379252912Sgonzo 1380252912Sgonzo if (td->transaction_started) { 1381252912Sgonzo musbotg_channel_free(sc, td); 1382252912Sgonzo return (0); /* complete */ 1383252912Sgonzo } 1384252912Sgonzo 1385252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_RXCSRH, MUSB2_MASK_CSR0H_PING_DIS); 1386252912Sgonzo 1387252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_TXFADDR(0), td->dev_addr); 1388252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_TXHADDR(0), td->haddr); 1389252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_TXHUBPORT(0), td->hport); 1390252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_TXTI, td->transfer_type); 1391252912Sgonzo 1392252912Sgonzo /* TX NAK timeout */ 1393252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_TXNAKLIMIT, MAX_NAK_TO); 1394252912Sgonzo 1395252912Sgonzo td->transaction_started = 1; 1396252912Sgonzo 1397252912Sgonzo /* write command */ 1398252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 1399252912Sgonzo MUSB2_MASK_CSR0L_STATUSPKT | 1400252912Sgonzo MUSB2_MASK_CSR0L_TXPKTRDY); 1401252912Sgonzo 1402252912Sgonzo return (1); /* wait for interrupt */ 1403252912Sgonzo} 1404252912Sgonzo 1405252912Sgonzostatic uint8_t 1406252912Sgonzomusbotg_dev_data_rx(struct musbotg_td *td) 1407252912Sgonzo{ 1408192984Sthompsa struct usb_page_search buf_res; 1409184610Salfred struct musbotg_softc *sc; 1410184610Salfred uint16_t count; 1411184610Salfred uint8_t csr; 1412184610Salfred uint8_t to; 1413184610Salfred uint8_t got_short; 1414184610Salfred 1415184610Salfred to = 8; /* don't loop forever! */ 1416184610Salfred got_short = 0; 1417184610Salfred 1418184610Salfred /* get pointer to softc */ 1419184610Salfred sc = MUSBOTG_PC2SC(td->pc); 1420184610Salfred 1421252912Sgonzo if (td->channel == -1) 1422252912Sgonzo td->channel = musbotg_channel_alloc(sc, td); 1423252912Sgonzo 1424252912Sgonzo /* EP0 is busy, wait */ 1425252912Sgonzo if (td->channel == -1) 1426252912Sgonzo return (1); 1427252912Sgonzo 1428184610Salfred /* select endpoint */ 1429252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_EPINDEX, td->channel); 1430184610Salfred 1431184610Salfredrepeat: 1432184610Salfred /* read out FIFO status */ 1433184610Salfred csr = MUSB2_READ_1(sc, MUSB2_REG_RXCSRL); 1434184610Salfred 1435184610Salfred DPRINTFN(4, "csr=0x%02x\n", csr); 1436184610Salfred 1437184610Salfred /* clear overrun */ 1438184610Salfred if (csr & MUSB2_MASK_CSRL_RXOVERRUN) { 1439184610Salfred /* make sure we don't clear "RXPKTRDY" */ 1440184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_RXCSRL, 1441184610Salfred MUSB2_MASK_CSRL_RXPKTRDY); 1442184610Salfred } 1443252912Sgonzo 1444184610Salfred /* check status */ 1445252912Sgonzo if (!(csr & MUSB2_MASK_CSRL_RXPKTRDY)) 1446252912Sgonzo return (1); /* not complete */ 1447252912Sgonzo 1448184610Salfred /* get the packet byte count */ 1449184610Salfred count = MUSB2_READ_2(sc, MUSB2_REG_RXCOUNT); 1450184610Salfred 1451184610Salfred DPRINTFN(4, "count=0x%04x\n", count); 1452184610Salfred 1453184610Salfred /* 1454184610Salfred * Check for short or invalid packet: 1455184610Salfred */ 1456184610Salfred if (count != td->max_frame_size) { 1457184610Salfred if (count < td->max_frame_size) { 1458184610Salfred /* we have a short packet */ 1459184610Salfred td->short_pkt = 1; 1460184610Salfred got_short = 1; 1461184610Salfred } else { 1462184610Salfred /* invalid USB packet */ 1463184610Salfred td->error = 1; 1464252912Sgonzo musbotg_channel_free(sc, td); 1465184610Salfred return (0); /* we are complete */ 1466184610Salfred } 1467184610Salfred } 1468184610Salfred /* verify the packet byte count */ 1469184610Salfred if (count > td->remainder) { 1470184610Salfred /* invalid USB packet */ 1471184610Salfred td->error = 1; 1472252912Sgonzo musbotg_channel_free(sc, td); 1473184610Salfred return (0); /* we are complete */ 1474184610Salfred } 1475184610Salfred while (count > 0) { 1476184610Salfred uint32_t temp; 1477184610Salfred 1478194228Sthompsa usbd_get_page(td->pc, td->offset, &buf_res); 1479184610Salfred 1480184610Salfred /* get correct length */ 1481184610Salfred if (buf_res.length > count) { 1482184610Salfred buf_res.length = count; 1483184610Salfred } 1484184610Salfred /* check for unaligned memory address */ 1485184610Salfred if (USB_P2U(buf_res.buffer) & 3) { 1486184610Salfred 1487184610Salfred temp = count & ~3; 1488184610Salfred 1489184610Salfred if (temp) { 1490184610Salfred /* receive data 4 bytes at a time */ 1491184610Salfred bus_space_read_multi_4(sc->sc_io_tag, sc->sc_io_hdl, 1492252912Sgonzo MUSB2_REG_EPFIFO(td->channel), sc->sc_bounce_buf, 1493184610Salfred temp / 4); 1494184610Salfred } 1495184610Salfred temp = count & 3; 1496184610Salfred if (temp) { 1497184610Salfred /* receive data 1 byte at a time */ 1498184610Salfred bus_space_read_multi_1(sc->sc_io_tag, 1499252912Sgonzo sc->sc_io_hdl, MUSB2_REG_EPFIFO(td->channel), 1500184610Salfred ((void *)&sc->sc_bounce_buf[count / 4]), temp); 1501184610Salfred } 1502194228Sthompsa usbd_copy_in(td->pc, td->offset, 1503184610Salfred sc->sc_bounce_buf, count); 1504184610Salfred 1505184610Salfred /* update offset and remainder */ 1506184610Salfred td->offset += count; 1507184610Salfred td->remainder -= count; 1508184610Salfred break; 1509184610Salfred } 1510184610Salfred /* check if we can optimise */ 1511184610Salfred if (buf_res.length >= 4) { 1512184610Salfred 1513184610Salfred /* receive data 4 bytes at a time */ 1514184610Salfred bus_space_read_multi_4(sc->sc_io_tag, sc->sc_io_hdl, 1515252912Sgonzo MUSB2_REG_EPFIFO(td->channel), buf_res.buffer, 1516184610Salfred buf_res.length / 4); 1517184610Salfred 1518184610Salfred temp = buf_res.length & ~3; 1519184610Salfred 1520184610Salfred /* update counters */ 1521184610Salfred count -= temp; 1522184610Salfred td->offset += temp; 1523184610Salfred td->remainder -= temp; 1524184610Salfred continue; 1525184610Salfred } 1526184610Salfred /* receive data */ 1527184610Salfred bus_space_read_multi_1(sc->sc_io_tag, sc->sc_io_hdl, 1528252912Sgonzo MUSB2_REG_EPFIFO(td->channel), buf_res.buffer, 1529184610Salfred buf_res.length); 1530184610Salfred 1531184610Salfred /* update counters */ 1532184610Salfred count -= buf_res.length; 1533184610Salfred td->offset += buf_res.length; 1534184610Salfred td->remainder -= buf_res.length; 1535184610Salfred } 1536184610Salfred 1537184610Salfred /* clear status bits */ 1538184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_RXCSRL, 0); 1539184610Salfred 1540184610Salfred /* check if we are complete */ 1541184610Salfred if ((td->remainder == 0) || got_short) { 1542184610Salfred if (td->short_pkt) { 1543184610Salfred /* we are complete */ 1544252912Sgonzo musbotg_channel_free(sc, td); 1545184610Salfred return (0); 1546184610Salfred } 1547184610Salfred /* else need to receive a zero length packet */ 1548184610Salfred } 1549184610Salfred if (--to) { 1550184610Salfred goto repeat; 1551184610Salfred } 1552184610Salfred return (1); /* not complete */ 1553184610Salfred} 1554184610Salfred 1555184610Salfredstatic uint8_t 1556252912Sgonzomusbotg_dev_data_tx(struct musbotg_td *td) 1557184610Salfred{ 1558192984Sthompsa struct usb_page_search buf_res; 1559184610Salfred struct musbotg_softc *sc; 1560184610Salfred uint16_t count; 1561184610Salfred uint8_t csr; 1562184610Salfred uint8_t to; 1563184610Salfred 1564184610Salfred to = 8; /* don't loop forever! */ 1565184610Salfred 1566184610Salfred /* get pointer to softc */ 1567184610Salfred sc = MUSBOTG_PC2SC(td->pc); 1568184610Salfred 1569252912Sgonzo if (td->channel == -1) 1570252912Sgonzo td->channel = musbotg_channel_alloc(sc, td); 1571252912Sgonzo 1572252912Sgonzo /* EP0 is busy, wait */ 1573252912Sgonzo if (td->channel == -1) 1574252912Sgonzo return (1); 1575252912Sgonzo 1576184610Salfred /* select endpoint */ 1577252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_EPINDEX, td->channel); 1578184610Salfred 1579184610Salfredrepeat: 1580184610Salfred 1581184610Salfred /* read out FIFO status */ 1582184610Salfred csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL); 1583184610Salfred 1584184610Salfred DPRINTFN(4, "csr=0x%02x\n", csr); 1585184610Salfred 1586184610Salfred if (csr & (MUSB2_MASK_CSRL_TXINCOMP | 1587184610Salfred MUSB2_MASK_CSRL_TXUNDERRUN)) { 1588184610Salfred /* clear status bits */ 1589184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 0); 1590184610Salfred } 1591184610Salfred if (csr & MUSB2_MASK_CSRL_TXPKTRDY) { 1592184610Salfred return (1); /* not complete */ 1593184610Salfred } 1594184610Salfred /* check for short packet */ 1595184610Salfred count = td->max_frame_size; 1596184610Salfred if (td->remainder < count) { 1597184610Salfred /* we have a short packet */ 1598184610Salfred td->short_pkt = 1; 1599184610Salfred count = td->remainder; 1600184610Salfred } 1601184610Salfred while (count > 0) { 1602184610Salfred uint32_t temp; 1603184610Salfred 1604194228Sthompsa usbd_get_page(td->pc, td->offset, &buf_res); 1605184610Salfred 1606184610Salfred /* get correct length */ 1607184610Salfred if (buf_res.length > count) { 1608184610Salfred buf_res.length = count; 1609184610Salfred } 1610184610Salfred /* check for unaligned memory address */ 1611184610Salfred if (USB_P2U(buf_res.buffer) & 3) { 1612184610Salfred 1613194228Sthompsa usbd_copy_out(td->pc, td->offset, 1614184610Salfred sc->sc_bounce_buf, count); 1615184610Salfred 1616184610Salfred temp = count & ~3; 1617184610Salfred 1618184610Salfred if (temp) { 1619184610Salfred /* transmit data 4 bytes at a time */ 1620184610Salfred bus_space_write_multi_4(sc->sc_io_tag, 1621252912Sgonzo sc->sc_io_hdl, MUSB2_REG_EPFIFO(td->channel), 1622184610Salfred sc->sc_bounce_buf, temp / 4); 1623184610Salfred } 1624184610Salfred temp = count & 3; 1625184610Salfred if (temp) { 1626184610Salfred /* receive data 1 byte at a time */ 1627184610Salfred bus_space_write_multi_1(sc->sc_io_tag, sc->sc_io_hdl, 1628252912Sgonzo MUSB2_REG_EPFIFO(td->channel), 1629184610Salfred ((void *)&sc->sc_bounce_buf[count / 4]), temp); 1630184610Salfred } 1631184610Salfred /* update offset and remainder */ 1632184610Salfred td->offset += count; 1633184610Salfred td->remainder -= count; 1634184610Salfred break; 1635184610Salfred } 1636184610Salfred /* check if we can optimise */ 1637184610Salfred if (buf_res.length >= 4) { 1638184610Salfred 1639184610Salfred /* transmit data 4 bytes at a time */ 1640184610Salfred bus_space_write_multi_4(sc->sc_io_tag, sc->sc_io_hdl, 1641252912Sgonzo MUSB2_REG_EPFIFO(td->channel), buf_res.buffer, 1642184610Salfred buf_res.length / 4); 1643184610Salfred 1644184610Salfred temp = buf_res.length & ~3; 1645184610Salfred 1646184610Salfred /* update counters */ 1647184610Salfred count -= temp; 1648184610Salfred td->offset += temp; 1649184610Salfred td->remainder -= temp; 1650184610Salfred continue; 1651184610Salfred } 1652184610Salfred /* transmit data */ 1653184610Salfred bus_space_write_multi_1(sc->sc_io_tag, sc->sc_io_hdl, 1654252912Sgonzo MUSB2_REG_EPFIFO(td->channel), buf_res.buffer, 1655184610Salfred buf_res.length); 1656184610Salfred 1657184610Salfred /* update counters */ 1658184610Salfred count -= buf_res.length; 1659184610Salfred td->offset += buf_res.length; 1660184610Salfred td->remainder -= buf_res.length; 1661184610Salfred } 1662184610Salfred 1663252912Sgonzo /* Max packet size */ 1664257043Shselasky MUSB2_WRITE_2(sc, MUSB2_REG_TXMAXP, td->reg_max_packet); 1665252912Sgonzo 1666184610Salfred /* write command */ 1667184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 1668184610Salfred MUSB2_MASK_CSRL_TXPKTRDY); 1669184610Salfred 1670184610Salfred /* check remainder */ 1671184610Salfred if (td->remainder == 0) { 1672184610Salfred if (td->short_pkt) { 1673252912Sgonzo musbotg_channel_free(sc, td); 1674184610Salfred return (0); /* complete */ 1675184610Salfred } 1676184610Salfred /* else we need to transmit a short packet */ 1677184610Salfred } 1678184610Salfred if (--to) { 1679184610Salfred goto repeat; 1680184610Salfred } 1681184610Salfred return (1); /* not complete */ 1682184610Salfred} 1683184610Salfred 1684184610Salfredstatic uint8_t 1685252912Sgonzomusbotg_host_data_rx(struct musbotg_td *td) 1686252912Sgonzo{ 1687252912Sgonzo struct usb_page_search buf_res; 1688252912Sgonzo struct musbotg_softc *sc; 1689252912Sgonzo uint16_t count; 1690252912Sgonzo uint8_t csr, csrh; 1691252912Sgonzo uint8_t to; 1692252912Sgonzo uint8_t got_short; 1693252912Sgonzo 1694252912Sgonzo /* get pointer to softc */ 1695252912Sgonzo sc = MUSBOTG_PC2SC(td->pc); 1696252912Sgonzo 1697252912Sgonzo if (td->channel == -1) 1698252912Sgonzo td->channel = musbotg_channel_alloc(sc, td); 1699252912Sgonzo 1700252912Sgonzo /* No free EPs */ 1701252912Sgonzo if (td->channel == -1) 1702252912Sgonzo return (1); 1703252912Sgonzo 1704252912Sgonzo DPRINTFN(1, "ep_no=%d\n", td->channel); 1705252912Sgonzo 1706252912Sgonzo to = 8; /* don't loop forever! */ 1707252912Sgonzo got_short = 0; 1708252912Sgonzo 1709252912Sgonzo /* select endpoint */ 1710252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_EPINDEX, td->channel); 1711252912Sgonzo 1712252912Sgonzorepeat: 1713252912Sgonzo /* read out FIFO status */ 1714252912Sgonzo csr = MUSB2_READ_1(sc, MUSB2_REG_RXCSRL); 1715252912Sgonzo DPRINTFN(4, "csr=0x%02x\n", csr); 1716252912Sgonzo 1717252912Sgonzo if (!td->transaction_started) { 1718252912Sgonzo /* Function address */ 1719252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_RXFADDR(td->channel), 1720252912Sgonzo td->dev_addr); 1721252912Sgonzo 1722252912Sgonzo /* SPLIT transaction */ 1723252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_RXHADDR(td->channel), 1724252912Sgonzo td->haddr); 1725252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_RXHUBPORT(td->channel), 1726252912Sgonzo td->hport); 1727252912Sgonzo 1728252912Sgonzo /* RX NAK timeout */ 1729257043Shselasky if (td->transfer_type & MUSB2_MASK_TI_PROTO_ISOC) 1730257043Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_RXNAKLIMIT, 0); 1731257043Shselasky else 1732257043Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_RXNAKLIMIT, MAX_NAK_TO); 1733252912Sgonzo 1734252912Sgonzo /* Protocol, speed, device endpoint */ 1735252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_RXTI, td->transfer_type); 1736252912Sgonzo 1737252912Sgonzo /* Max packet size */ 1738257043Shselasky MUSB2_WRITE_2(sc, MUSB2_REG_RXMAXP, td->reg_max_packet); 1739252912Sgonzo 1740252912Sgonzo /* Data Toggle */ 1741252912Sgonzo csrh = MUSB2_READ_1(sc, MUSB2_REG_RXCSRH); 1742252912Sgonzo DPRINTFN(4, "csrh=0x%02x\n", csrh); 1743252912Sgonzo 1744252912Sgonzo csrh |= MUSB2_MASK_CSRH_RXDT_WREN; 1745252912Sgonzo if (td->toggle) 1746252912Sgonzo csrh |= MUSB2_MASK_CSRH_RXDT_VAL; 1747252912Sgonzo else 1748252912Sgonzo csrh &= ~MUSB2_MASK_CSRH_RXDT_VAL; 1749252912Sgonzo 1750252912Sgonzo /* Set data toggle */ 1751252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_RXCSRH, csrh); 1752252912Sgonzo 1753252912Sgonzo /* write command */ 1754252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_RXCSRL, 1755252912Sgonzo MUSB2_MASK_CSRL_RXREQPKT); 1756252912Sgonzo 1757252912Sgonzo td->transaction_started = 1; 1758252912Sgonzo return (1); 1759252912Sgonzo } 1760252912Sgonzo 1761252912Sgonzo /* clear NAK timeout */ 1762252912Sgonzo if (csr & MUSB2_MASK_CSRL_RXNAKTO) { 1763252912Sgonzo DPRINTFN(4, "NAK Timeout\n"); 1764252912Sgonzo if (csr & MUSB2_MASK_CSRL_RXREQPKT) { 1765252912Sgonzo csr &= ~MUSB2_MASK_CSRL_RXREQPKT; 1766252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_RXCSRL, csr); 1767252912Sgonzo 1768252912Sgonzo csr &= ~MUSB2_MASK_CSRL_RXNAKTO; 1769252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_RXCSRL, csr); 1770252912Sgonzo } 1771252912Sgonzo 1772252912Sgonzo td->error = 1; 1773252912Sgonzo } 1774252912Sgonzo 1775252912Sgonzo if (csr & MUSB2_MASK_CSRL_RXERROR) { 1776252912Sgonzo DPRINTFN(4, "RXERROR\n"); 1777252912Sgonzo td->error = 1; 1778252912Sgonzo } 1779252912Sgonzo 1780252912Sgonzo if (csr & MUSB2_MASK_CSRL_RXSTALL) { 1781252912Sgonzo DPRINTFN(4, "RXSTALL\n"); 1782252912Sgonzo td->error = 1; 1783252912Sgonzo } 1784252912Sgonzo 1785252912Sgonzo if (td->error) { 1786252912Sgonzo musbotg_channel_free(sc, td); 1787252912Sgonzo return (0); /* we are complete */ 1788252912Sgonzo } 1789252912Sgonzo 1790252912Sgonzo if (!(csr & MUSB2_MASK_CSRL_RXPKTRDY)) { 1791252912Sgonzo /* No data available yet */ 1792252912Sgonzo return (1); 1793252912Sgonzo } 1794252912Sgonzo 1795252912Sgonzo td->toggle ^= 1; 1796252912Sgonzo /* get the packet byte count */ 1797252912Sgonzo count = MUSB2_READ_2(sc, MUSB2_REG_RXCOUNT); 1798252912Sgonzo DPRINTFN(4, "count=0x%04x\n", count); 1799252912Sgonzo 1800252912Sgonzo /* 1801252912Sgonzo * Check for short or invalid packet: 1802252912Sgonzo */ 1803252912Sgonzo if (count != td->max_frame_size) { 1804252912Sgonzo if (count < td->max_frame_size) { 1805252912Sgonzo /* we have a short packet */ 1806252912Sgonzo td->short_pkt = 1; 1807252912Sgonzo got_short = 1; 1808252912Sgonzo } else { 1809252912Sgonzo /* invalid USB packet */ 1810252912Sgonzo td->error = 1; 1811252912Sgonzo musbotg_channel_free(sc, td); 1812252912Sgonzo return (0); /* we are complete */ 1813252912Sgonzo } 1814252912Sgonzo } 1815252912Sgonzo 1816252912Sgonzo /* verify the packet byte count */ 1817252912Sgonzo if (count > td->remainder) { 1818252912Sgonzo /* invalid USB packet */ 1819252912Sgonzo td->error = 1; 1820252912Sgonzo musbotg_channel_free(sc, td); 1821252912Sgonzo return (0); /* we are complete */ 1822252912Sgonzo } 1823252912Sgonzo 1824252912Sgonzo while (count > 0) { 1825252912Sgonzo uint32_t temp; 1826252912Sgonzo 1827252912Sgonzo usbd_get_page(td->pc, td->offset, &buf_res); 1828252912Sgonzo 1829252912Sgonzo /* get correct length */ 1830252912Sgonzo if (buf_res.length > count) { 1831252912Sgonzo buf_res.length = count; 1832252912Sgonzo } 1833252912Sgonzo /* check for unaligned memory address */ 1834252912Sgonzo if (USB_P2U(buf_res.buffer) & 3) { 1835252912Sgonzo 1836252912Sgonzo temp = count & ~3; 1837252912Sgonzo 1838252912Sgonzo if (temp) { 1839252912Sgonzo /* receive data 4 bytes at a time */ 1840252912Sgonzo bus_space_read_multi_4(sc->sc_io_tag, sc->sc_io_hdl, 1841252912Sgonzo MUSB2_REG_EPFIFO(td->channel), sc->sc_bounce_buf, 1842252912Sgonzo temp / 4); 1843252912Sgonzo } 1844252912Sgonzo temp = count & 3; 1845252912Sgonzo if (temp) { 1846252912Sgonzo /* receive data 1 byte at a time */ 1847252912Sgonzo bus_space_read_multi_1(sc->sc_io_tag, 1848252912Sgonzo sc->sc_io_hdl, MUSB2_REG_EPFIFO(td->channel), 1849252912Sgonzo ((void *)&sc->sc_bounce_buf[count / 4]), temp); 1850252912Sgonzo } 1851252912Sgonzo usbd_copy_in(td->pc, td->offset, 1852252912Sgonzo sc->sc_bounce_buf, count); 1853252912Sgonzo 1854252912Sgonzo /* update offset and remainder */ 1855252912Sgonzo td->offset += count; 1856252912Sgonzo td->remainder -= count; 1857252912Sgonzo break; 1858252912Sgonzo } 1859252912Sgonzo /* check if we can optimise */ 1860252912Sgonzo if (buf_res.length >= 4) { 1861252912Sgonzo 1862252912Sgonzo /* receive data 4 bytes at a time */ 1863252912Sgonzo bus_space_read_multi_4(sc->sc_io_tag, sc->sc_io_hdl, 1864252912Sgonzo MUSB2_REG_EPFIFO(td->channel), buf_res.buffer, 1865252912Sgonzo buf_res.length / 4); 1866252912Sgonzo 1867252912Sgonzo temp = buf_res.length & ~3; 1868252912Sgonzo 1869252912Sgonzo /* update counters */ 1870252912Sgonzo count -= temp; 1871252912Sgonzo td->offset += temp; 1872252912Sgonzo td->remainder -= temp; 1873252912Sgonzo continue; 1874252912Sgonzo } 1875252912Sgonzo /* receive data */ 1876252912Sgonzo bus_space_read_multi_1(sc->sc_io_tag, sc->sc_io_hdl, 1877252912Sgonzo MUSB2_REG_EPFIFO(td->channel), buf_res.buffer, 1878252912Sgonzo buf_res.length); 1879252912Sgonzo 1880252912Sgonzo /* update counters */ 1881252912Sgonzo count -= buf_res.length; 1882252912Sgonzo td->offset += buf_res.length; 1883252912Sgonzo td->remainder -= buf_res.length; 1884252912Sgonzo } 1885252912Sgonzo 1886252912Sgonzo /* clear status bits */ 1887252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_RXCSRL, 0); 1888252912Sgonzo 1889252912Sgonzo /* check if we are complete */ 1890252912Sgonzo if ((td->remainder == 0) || got_short) { 1891252912Sgonzo if (td->short_pkt) { 1892252912Sgonzo /* we are complete */ 1893252912Sgonzo musbotg_channel_free(sc, td); 1894252912Sgonzo return (0); 1895252912Sgonzo } 1896252912Sgonzo /* else need to receive a zero length packet */ 1897252912Sgonzo } 1898252912Sgonzo 1899252912Sgonzo /* Reset transaction state and restart */ 1900252912Sgonzo td->transaction_started = 0; 1901252912Sgonzo 1902252912Sgonzo if (--to) 1903252912Sgonzo goto repeat; 1904252912Sgonzo 1905252912Sgonzo return (1); /* not complete */ 1906252912Sgonzo} 1907252912Sgonzo 1908252912Sgonzostatic uint8_t 1909252912Sgonzomusbotg_host_data_tx(struct musbotg_td *td) 1910252912Sgonzo{ 1911252912Sgonzo struct usb_page_search buf_res; 1912252912Sgonzo struct musbotg_softc *sc; 1913252912Sgonzo uint16_t count; 1914252912Sgonzo uint8_t csr, csrh; 1915252912Sgonzo 1916252912Sgonzo /* get pointer to softc */ 1917252912Sgonzo sc = MUSBOTG_PC2SC(td->pc); 1918252912Sgonzo 1919252912Sgonzo if (td->channel == -1) 1920252912Sgonzo td->channel = musbotg_channel_alloc(sc, td); 1921252912Sgonzo 1922252912Sgonzo /* No free EPs */ 1923252912Sgonzo if (td->channel == -1) 1924252912Sgonzo return (1); 1925252912Sgonzo 1926252912Sgonzo DPRINTFN(1, "ep_no=%d\n", td->channel); 1927252912Sgonzo 1928252912Sgonzo /* select endpoint */ 1929252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_EPINDEX, td->channel); 1930252912Sgonzo 1931252912Sgonzo /* read out FIFO status */ 1932252912Sgonzo csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL); 1933252912Sgonzo DPRINTFN(4, "csr=0x%02x\n", csr); 1934252912Sgonzo 1935252912Sgonzo if (csr & (MUSB2_MASK_CSRL_TXSTALLED | 1936252912Sgonzo MUSB2_MASK_CSRL_TXERROR)) { 1937252912Sgonzo /* clear status bits */ 1938252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 0); 1939252912Sgonzo td->error = 1; 1940252912Sgonzo musbotg_channel_free(sc, td); 1941252912Sgonzo return (0); /* complete */ 1942252912Sgonzo } 1943252912Sgonzo 1944257043Shselasky if (csr & MUSB2_MASK_CSRL_TXNAKTO) { 1945252912Sgonzo /* 1946252912Sgonzo * Flush TX FIFO before clearing NAK TO 1947252912Sgonzo */ 1948252912Sgonzo if (csr & MUSB2_MASK_CSRL_TXFIFONEMPTY) { 1949252912Sgonzo csr |= MUSB2_MASK_CSRL_TXFFLUSH; 1950252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, csr); 1951252912Sgonzo csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL); 1952252912Sgonzo if (csr & MUSB2_MASK_CSRL_TXFIFONEMPTY) { 1953252912Sgonzo csr |= MUSB2_MASK_CSRL_TXFFLUSH; 1954252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, csr); 1955252912Sgonzo csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL); 1956252912Sgonzo } 1957252912Sgonzo } 1958252912Sgonzo 1959252912Sgonzo csr &= ~MUSB2_MASK_CSRL_TXNAKTO; 1960252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, csr); 1961252912Sgonzo 1962252912Sgonzo td->error = 1; 1963252912Sgonzo musbotg_channel_free(sc, td); 1964252912Sgonzo return (0); /* complete */ 1965252912Sgonzo } 1966252912Sgonzo 1967252912Sgonzo /* 1968252912Sgonzo * Wait while FIFO is empty. 1969252912Sgonzo * Do not flush it because it will cause transactions 1970252912Sgonzo * with size more then packet size. It might upset 1971252912Sgonzo * some devices 1972252912Sgonzo */ 1973252912Sgonzo if (csr & MUSB2_MASK_CSRL_TXFIFONEMPTY) 1974252912Sgonzo return (1); 1975252912Sgonzo 1976252912Sgonzo /* Packet still being processed */ 1977252912Sgonzo if (csr & MUSB2_MASK_CSRL_TXPKTRDY) 1978252912Sgonzo return (1); 1979252912Sgonzo 1980252912Sgonzo if (td->transaction_started) { 1981252912Sgonzo /* check remainder */ 1982252912Sgonzo if (td->remainder == 0) { 1983252912Sgonzo if (td->short_pkt) { 1984252912Sgonzo musbotg_channel_free(sc, td); 1985252912Sgonzo return (0); /* complete */ 1986252912Sgonzo } 1987252912Sgonzo /* else we need to transmit a short packet */ 1988252912Sgonzo } 1989252912Sgonzo 1990252912Sgonzo /* We're not complete - more transactions required */ 1991252912Sgonzo td->transaction_started = 0; 1992252912Sgonzo } 1993252912Sgonzo 1994252912Sgonzo /* check for short packet */ 1995252912Sgonzo count = td->max_frame_size; 1996252912Sgonzo if (td->remainder < count) { 1997252912Sgonzo /* we have a short packet */ 1998252912Sgonzo td->short_pkt = 1; 1999252912Sgonzo count = td->remainder; 2000252912Sgonzo } 2001252912Sgonzo 2002252912Sgonzo while (count > 0) { 2003252912Sgonzo uint32_t temp; 2004252912Sgonzo 2005252912Sgonzo usbd_get_page(td->pc, td->offset, &buf_res); 2006252912Sgonzo 2007252912Sgonzo /* get correct length */ 2008252912Sgonzo if (buf_res.length > count) { 2009252912Sgonzo buf_res.length = count; 2010252912Sgonzo } 2011252912Sgonzo /* check for unaligned memory address */ 2012252912Sgonzo if (USB_P2U(buf_res.buffer) & 3) { 2013252912Sgonzo 2014252912Sgonzo usbd_copy_out(td->pc, td->offset, 2015252912Sgonzo sc->sc_bounce_buf, count); 2016252912Sgonzo 2017252912Sgonzo temp = count & ~3; 2018252912Sgonzo 2019252912Sgonzo if (temp) { 2020252912Sgonzo /* transmit data 4 bytes at a time */ 2021252912Sgonzo bus_space_write_multi_4(sc->sc_io_tag, 2022252912Sgonzo sc->sc_io_hdl, MUSB2_REG_EPFIFO(td->channel), 2023252912Sgonzo sc->sc_bounce_buf, temp / 4); 2024252912Sgonzo } 2025252912Sgonzo temp = count & 3; 2026252912Sgonzo if (temp) { 2027252912Sgonzo /* receive data 1 byte at a time */ 2028252912Sgonzo bus_space_write_multi_1(sc->sc_io_tag, sc->sc_io_hdl, 2029252912Sgonzo MUSB2_REG_EPFIFO(td->channel), 2030252912Sgonzo ((void *)&sc->sc_bounce_buf[count / 4]), temp); 2031252912Sgonzo } 2032252912Sgonzo /* update offset and remainder */ 2033252912Sgonzo td->offset += count; 2034252912Sgonzo td->remainder -= count; 2035252912Sgonzo break; 2036252912Sgonzo } 2037252912Sgonzo /* check if we can optimise */ 2038252912Sgonzo if (buf_res.length >= 4) { 2039252912Sgonzo 2040252912Sgonzo /* transmit data 4 bytes at a time */ 2041252912Sgonzo bus_space_write_multi_4(sc->sc_io_tag, sc->sc_io_hdl, 2042252912Sgonzo MUSB2_REG_EPFIFO(td->channel), buf_res.buffer, 2043252912Sgonzo buf_res.length / 4); 2044252912Sgonzo 2045252912Sgonzo temp = buf_res.length & ~3; 2046252912Sgonzo 2047252912Sgonzo /* update counters */ 2048252912Sgonzo count -= temp; 2049252912Sgonzo td->offset += temp; 2050252912Sgonzo td->remainder -= temp; 2051252912Sgonzo continue; 2052252912Sgonzo } 2053252912Sgonzo /* transmit data */ 2054252912Sgonzo bus_space_write_multi_1(sc->sc_io_tag, sc->sc_io_hdl, 2055252912Sgonzo MUSB2_REG_EPFIFO(td->channel), buf_res.buffer, 2056252912Sgonzo buf_res.length); 2057252912Sgonzo 2058252912Sgonzo /* update counters */ 2059252912Sgonzo count -= buf_res.length; 2060252912Sgonzo td->offset += buf_res.length; 2061252912Sgonzo td->remainder -= buf_res.length; 2062252912Sgonzo } 2063252912Sgonzo 2064252912Sgonzo /* Function address */ 2065252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_TXFADDR(td->channel), 2066252912Sgonzo td->dev_addr); 2067252912Sgonzo 2068252912Sgonzo /* SPLIT transaction */ 2069252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_TXHADDR(td->channel), 2070252912Sgonzo td->haddr); 2071252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_TXHUBPORT(td->channel), 2072252912Sgonzo td->hport); 2073252912Sgonzo 2074252912Sgonzo /* TX NAK timeout */ 2075257043Shselasky if (td->transfer_type & MUSB2_MASK_TI_PROTO_ISOC) 2076257043Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_TXNAKLIMIT, 0); 2077257043Shselasky else 2078257043Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_TXNAKLIMIT, MAX_NAK_TO); 2079252912Sgonzo 2080252912Sgonzo /* Protocol, speed, device endpoint */ 2081252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_TXTI, td->transfer_type); 2082252912Sgonzo 2083252912Sgonzo /* Max packet size */ 2084257043Shselasky MUSB2_WRITE_2(sc, MUSB2_REG_TXMAXP, td->reg_max_packet); 2085252912Sgonzo 2086252912Sgonzo if (!td->transaction_started) { 2087252912Sgonzo csrh = MUSB2_READ_1(sc, MUSB2_REG_TXCSRH); 2088252912Sgonzo DPRINTFN(4, "csrh=0x%02x\n", csrh); 2089252912Sgonzo 2090252912Sgonzo csrh |= MUSB2_MASK_CSRH_TXDT_WREN; 2091252912Sgonzo if (td->toggle) 2092252912Sgonzo csrh |= MUSB2_MASK_CSRH_TXDT_VAL; 2093252912Sgonzo else 2094252912Sgonzo csrh &= ~MUSB2_MASK_CSRH_TXDT_VAL; 2095252912Sgonzo 2096252912Sgonzo /* Set data toggle */ 2097252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRH, csrh); 2098252912Sgonzo } 2099252912Sgonzo 2100252912Sgonzo /* write command */ 2101252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 2102252912Sgonzo MUSB2_MASK_CSRL_TXPKTRDY); 2103252912Sgonzo 2104252912Sgonzo /* Update Data Toggle */ 2105252912Sgonzo td->toggle ^= 1; 2106252912Sgonzo td->transaction_started = 1; 2107252912Sgonzo 2108252912Sgonzo return (1); /* not complete */ 2109252912Sgonzo} 2110252912Sgonzo 2111252912Sgonzostatic uint8_t 2112192984Sthompsamusbotg_xfer_do_fifo(struct usb_xfer *xfer) 2113184610Salfred{ 2114184610Salfred struct musbotg_softc *sc; 2115184610Salfred struct musbotg_td *td; 2116184610Salfred 2117184610Salfred DPRINTFN(8, "\n"); 2118252912Sgonzo sc = MUSBOTG_BUS2SC(xfer->xroot->bus); 2119184610Salfred 2120184610Salfred td = xfer->td_transfer_cache; 2121184610Salfred while (1) { 2122252912Sgonzo 2123184610Salfred if ((td->func) (td)) { 2124184610Salfred /* operation in progress */ 2125184610Salfred break; 2126184610Salfred } 2127252912Sgonzo 2128184610Salfred if (((void *)td) == xfer->td_transfer_last) { 2129184610Salfred goto done; 2130184610Salfred } 2131184610Salfred if (td->error) { 2132184610Salfred goto done; 2133184610Salfred } else if (td->remainder > 0) { 2134184610Salfred /* 2135184610Salfred * We had a short transfer. If there is no alternate 2136184610Salfred * next, stop processing ! 2137184610Salfred */ 2138184610Salfred if (!td->alt_next) { 2139184610Salfred goto done; 2140184610Salfred } 2141184610Salfred } 2142184610Salfred /* 2143184610Salfred * Fetch the next transfer descriptor and transfer 2144184610Salfred * some flags to the next transfer descriptor 2145184610Salfred */ 2146184610Salfred td = td->obj_next; 2147184610Salfred xfer->td_transfer_cache = td; 2148184610Salfred } 2149252912Sgonzo 2150184610Salfred return (1); /* not complete */ 2151184610Salfreddone: 2152184610Salfred /* compute all actual lengths */ 2153184610Salfred musbotg_standard_done(xfer); 2154184610Salfred 2155184610Salfred return (0); /* complete */ 2156184610Salfred} 2157184610Salfred 2158184610Salfredstatic void 2159184610Salfredmusbotg_interrupt_poll(struct musbotg_softc *sc) 2160184610Salfred{ 2161192984Sthompsa struct usb_xfer *xfer; 2162184610Salfred 2163184610Salfredrepeat: 2164184610Salfred TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) { 2165184610Salfred if (!musbotg_xfer_do_fifo(xfer)) { 2166184610Salfred /* queue has been modified */ 2167184610Salfred goto repeat; 2168184610Salfred } 2169184610Salfred } 2170184610Salfred} 2171184610Salfred 2172187175Sthompsavoid 2173187175Sthompsamusbotg_vbus_interrupt(struct musbotg_softc *sc, uint8_t is_on) 2174184610Salfred{ 2175184610Salfred DPRINTFN(4, "vbus = %u\n", is_on); 2176184610Salfred 2177184824Sthompsa USB_BUS_LOCK(&sc->sc_bus); 2178184610Salfred if (is_on) { 2179184610Salfred if (!sc->sc_flags.status_vbus) { 2180184610Salfred sc->sc_flags.status_vbus = 1; 2181184610Salfred 2182184610Salfred /* complete root HUB interrupt endpoint */ 2183190735Sthompsa musbotg_root_intr(sc); 2184184610Salfred } 2185184610Salfred } else { 2186184610Salfred if (sc->sc_flags.status_vbus) { 2187184610Salfred sc->sc_flags.status_vbus = 0; 2188184610Salfred sc->sc_flags.status_bus_reset = 0; 2189184610Salfred sc->sc_flags.status_suspend = 0; 2190184610Salfred sc->sc_flags.change_suspend = 0; 2191184610Salfred sc->sc_flags.change_connect = 1; 2192184610Salfred 2193184610Salfred /* complete root HUB interrupt endpoint */ 2194190735Sthompsa musbotg_root_intr(sc); 2195184610Salfred } 2196184610Salfred } 2197184610Salfred 2198184824Sthompsa USB_BUS_UNLOCK(&sc->sc_bus); 2199184610Salfred} 2200184610Salfred 2201184610Salfredvoid 2202252912Sgonzomusbotg_connect_interrupt(struct musbotg_softc *sc) 2203184610Salfred{ 2204252912Sgonzo USB_BUS_LOCK(&sc->sc_bus); 2205252912Sgonzo sc->sc_flags.change_connect = 1; 2206252912Sgonzo 2207252912Sgonzo /* complete root HUB interrupt endpoint */ 2208252912Sgonzo musbotg_root_intr(sc); 2209252912Sgonzo USB_BUS_UNLOCK(&sc->sc_bus); 2210252912Sgonzo} 2211252912Sgonzo 2212252912Sgonzovoid 2213252912Sgonzomusbotg_interrupt(struct musbotg_softc *sc, 2214252912Sgonzo uint16_t rxstat, uint16_t txstat, uint8_t stat) 2215252912Sgonzo{ 2216184610Salfred uint16_t rx_status; 2217184610Salfred uint16_t tx_status; 2218184610Salfred uint8_t usb_status; 2219184610Salfred uint8_t temp; 2220184610Salfred uint8_t to = 2; 2221184610Salfred 2222184824Sthompsa USB_BUS_LOCK(&sc->sc_bus); 2223184610Salfred 2224184610Salfredrepeat: 2225184610Salfred 2226184610Salfred /* read all interrupt registers */ 2227184610Salfred usb_status = MUSB2_READ_1(sc, MUSB2_REG_INTUSB); 2228184610Salfred 2229184610Salfred /* read all FIFO interrupts */ 2230184610Salfred rx_status = MUSB2_READ_2(sc, MUSB2_REG_INTRX); 2231184610Salfred tx_status = MUSB2_READ_2(sc, MUSB2_REG_INTTX); 2232252912Sgonzo rx_status |= rxstat; 2233252912Sgonzo tx_status |= txstat; 2234252912Sgonzo usb_status |= stat; 2235184610Salfred 2236252912Sgonzo /* Clear platform flags after first time */ 2237252912Sgonzo rxstat = 0; 2238252912Sgonzo txstat = 0; 2239252912Sgonzo stat = 0; 2240252912Sgonzo 2241184610Salfred /* check for any bus state change interrupts */ 2242184610Salfred 2243184610Salfred if (usb_status & (MUSB2_MASK_IRESET | 2244252912Sgonzo MUSB2_MASK_IRESUME | MUSB2_MASK_ISUSP | 2245252912Sgonzo MUSB2_MASK_ICONN | MUSB2_MASK_IDISC)) { 2246184610Salfred 2247184610Salfred DPRINTFN(4, "real bus interrupt 0x%08x\n", usb_status); 2248184610Salfred 2249184610Salfred if (usb_status & MUSB2_MASK_IRESET) { 2250184610Salfred 2251184610Salfred /* set correct state */ 2252184610Salfred sc->sc_flags.status_bus_reset = 1; 2253184610Salfred sc->sc_flags.status_suspend = 0; 2254184610Salfred sc->sc_flags.change_suspend = 0; 2255184610Salfred sc->sc_flags.change_connect = 1; 2256184610Salfred 2257184610Salfred /* determine line speed */ 2258184610Salfred temp = MUSB2_READ_1(sc, MUSB2_REG_POWER); 2259184610Salfred if (temp & MUSB2_MASK_HSMODE) 2260184610Salfred sc->sc_flags.status_high_speed = 1; 2261184610Salfred else 2262184610Salfred sc->sc_flags.status_high_speed = 0; 2263184610Salfred 2264184610Salfred /* 2265184610Salfred * After reset all interrupts are on and we need to 2266184610Salfred * turn them off! 2267184610Salfred */ 2268184610Salfred temp = MUSB2_MASK_IRESET; 2269184610Salfred /* disable resume interrupt */ 2270184610Salfred temp &= ~MUSB2_MASK_IRESUME; 2271184610Salfred /* enable suspend interrupt */ 2272184610Salfred temp |= MUSB2_MASK_ISUSP; 2273184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_INTUSBE, temp); 2274184610Salfred /* disable TX and RX interrupts */ 2275184610Salfred MUSB2_WRITE_2(sc, MUSB2_REG_INTTXE, 0); 2276184610Salfred MUSB2_WRITE_2(sc, MUSB2_REG_INTRXE, 0); 2277184610Salfred } 2278184610Salfred /* 2279184610Salfred * If RXRSM and RXSUSP is set at the same time we interpret 2280184610Salfred * that like RESUME. Resume is set when there is at least 3 2281184610Salfred * milliseconds of inactivity on the USB BUS. 2282184610Salfred */ 2283184610Salfred if (usb_status & MUSB2_MASK_IRESUME) { 2284184610Salfred if (sc->sc_flags.status_suspend) { 2285184610Salfred sc->sc_flags.status_suspend = 0; 2286184610Salfred sc->sc_flags.change_suspend = 1; 2287184610Salfred 2288184610Salfred temp = MUSB2_READ_1(sc, MUSB2_REG_INTUSBE); 2289184610Salfred /* disable resume interrupt */ 2290184610Salfred temp &= ~MUSB2_MASK_IRESUME; 2291184610Salfred /* enable suspend interrupt */ 2292184610Salfred temp |= MUSB2_MASK_ISUSP; 2293184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_INTUSBE, temp); 2294184610Salfred } 2295184610Salfred } else if (usb_status & MUSB2_MASK_ISUSP) { 2296184610Salfred if (!sc->sc_flags.status_suspend) { 2297184610Salfred sc->sc_flags.status_suspend = 1; 2298184610Salfred sc->sc_flags.change_suspend = 1; 2299184610Salfred 2300184610Salfred temp = MUSB2_READ_1(sc, MUSB2_REG_INTUSBE); 2301184610Salfred /* disable suspend interrupt */ 2302184610Salfred temp &= ~MUSB2_MASK_ISUSP; 2303184610Salfred /* enable resume interrupt */ 2304184610Salfred temp |= MUSB2_MASK_IRESUME; 2305184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_INTUSBE, temp); 2306184610Salfred } 2307184610Salfred } 2308252912Sgonzo if (usb_status & 2309252912Sgonzo (MUSB2_MASK_ICONN | MUSB2_MASK_IDISC)) 2310252912Sgonzo sc->sc_flags.change_connect = 1; 2311252912Sgonzo 2312252912Sgonzo /* 2313252912Sgonzo * Host Mode: There is no IRESET so assume bus is 2314252912Sgonzo * always in reset state once device is connected. 2315252912Sgonzo */ 2316252912Sgonzo if (sc->sc_mode == MUSB2_HOST_MODE) { 2317252912Sgonzo if (usb_status & MUSB2_MASK_ICONN) 2318252912Sgonzo sc->sc_flags.status_bus_reset = 1; 2319252912Sgonzo if (usb_status & MUSB2_MASK_IDISC) 2320252912Sgonzo sc->sc_flags.status_bus_reset = 0; 2321252912Sgonzo } 2322252912Sgonzo 2323184610Salfred /* complete root HUB interrupt endpoint */ 2324190735Sthompsa musbotg_root_intr(sc); 2325184610Salfred } 2326184610Salfred /* check for any endpoint interrupts */ 2327184610Salfred 2328184610Salfred if (rx_status || tx_status) { 2329184610Salfred DPRINTFN(4, "real endpoint interrupt " 2330184610Salfred "rx=0x%04x, tx=0x%04x\n", rx_status, tx_status); 2331184610Salfred } 2332184610Salfred /* poll one time regardless of FIFO status */ 2333184610Salfred 2334184610Salfred musbotg_interrupt_poll(sc); 2335184610Salfred 2336184610Salfred if (--to) 2337184610Salfred goto repeat; 2338184610Salfred 2339184824Sthompsa USB_BUS_UNLOCK(&sc->sc_bus); 2340184610Salfred} 2341184610Salfred 2342184610Salfredstatic void 2343184610Salfredmusbotg_setup_standard_chain_sub(struct musbotg_std_temp *temp) 2344184610Salfred{ 2345184610Salfred struct musbotg_td *td; 2346184610Salfred 2347184610Salfred /* get current Transfer Descriptor */ 2348184610Salfred td = temp->td_next; 2349184610Salfred temp->td = td; 2350184610Salfred 2351184610Salfred /* prepare for next TD */ 2352184610Salfred temp->td_next = td->obj_next; 2353184610Salfred 2354184610Salfred /* fill out the Transfer Descriptor */ 2355184610Salfred td->func = temp->func; 2356184610Salfred td->pc = temp->pc; 2357184610Salfred td->offset = temp->offset; 2358184610Salfred td->remainder = temp->len; 2359184610Salfred td->error = 0; 2360252912Sgonzo td->transaction_started = 0; 2361192552Sthompsa td->did_stall = temp->did_stall; 2362184610Salfred td->short_pkt = temp->short_pkt; 2363184610Salfred td->alt_next = temp->setup_alt_next; 2364252912Sgonzo td->channel = temp->channel; 2365252912Sgonzo td->dev_addr = temp->dev_addr; 2366252912Sgonzo td->haddr = temp->haddr; 2367252912Sgonzo td->hport = temp->hport; 2368252912Sgonzo td->transfer_type = temp->transfer_type; 2369184610Salfred} 2370184610Salfred 2371184610Salfredstatic void 2372192984Sthompsamusbotg_setup_standard_chain(struct usb_xfer *xfer) 2373184610Salfred{ 2374184610Salfred struct musbotg_std_temp temp; 2375184610Salfred struct musbotg_softc *sc; 2376184610Salfred struct musbotg_td *td; 2377184610Salfred uint32_t x; 2378184610Salfred uint8_t ep_no; 2379252912Sgonzo uint8_t xfer_type; 2380252912Sgonzo enum usb_dev_speed speed; 2381252912Sgonzo int tx; 2382252912Sgonzo int dev_addr; 2383184610Salfred 2384184610Salfred DPRINTFN(8, "addr=%d endpt=%d sumlen=%d speed=%d\n", 2385193644Sthompsa xfer->address, UE_GET_ADDR(xfer->endpointno), 2386194228Sthompsa xfer->sumlen, usbd_get_speed(xfer->xroot->udev)); 2387184610Salfred 2388252912Sgonzo sc = MUSBOTG_BUS2SC(xfer->xroot->bus); 2389252912Sgonzo ep_no = (xfer->endpointno & UE_ADDR); 2390252912Sgonzo 2391184610Salfred temp.max_frame_size = xfer->max_frame_size; 2392184610Salfred 2393184610Salfred td = xfer->td_start[0]; 2394184610Salfred xfer->td_transfer_first = td; 2395184610Salfred xfer->td_transfer_cache = td; 2396184610Salfred 2397184610Salfred /* setup temp */ 2398252912Sgonzo dev_addr = xfer->address; 2399184610Salfred 2400252912Sgonzo xfer_type = xfer->endpoint->edesc->bmAttributes & UE_XFERTYPE; 2401252912Sgonzo 2402199673Sthompsa temp.pc = NULL; 2403184610Salfred temp.td = NULL; 2404184610Salfred temp.td_next = xfer->td_start[0]; 2405190183Sthompsa temp.offset = 0; 2406184610Salfred temp.setup_alt_next = xfer->flags_int.short_frames_ok; 2407192552Sthompsa temp.did_stall = !xfer->flags_int.control_stall; 2408252912Sgonzo temp.channel = -1; 2409252912Sgonzo temp.dev_addr = dev_addr; 2410252912Sgonzo temp.haddr = xfer->xroot->udev->hs_hub_addr; 2411252912Sgonzo temp.hport = xfer->xroot->udev->hs_port_no; 2412184610Salfred 2413252912Sgonzo if (xfer->flags_int.usb_mode == USB_MODE_HOST) { 2414252912Sgonzo speed = usbd_get_speed(xfer->xroot->udev); 2415184610Salfred 2416252912Sgonzo switch (speed) { 2417252912Sgonzo case USB_SPEED_LOW: 2418252912Sgonzo temp.transfer_type = MUSB2_MASK_TI_SPEED_LO; 2419252912Sgonzo break; 2420252912Sgonzo case USB_SPEED_FULL: 2421252912Sgonzo temp.transfer_type = MUSB2_MASK_TI_SPEED_FS; 2422252912Sgonzo break; 2423252912Sgonzo case USB_SPEED_HIGH: 2424252912Sgonzo temp.transfer_type = MUSB2_MASK_TI_SPEED_HS; 2425252912Sgonzo break; 2426252912Sgonzo default: 2427252912Sgonzo temp.transfer_type = 0; 2428252912Sgonzo DPRINTFN(-1, "Invalid USB speed: %d\n", speed); 2429252912Sgonzo break; 2430252912Sgonzo } 2431252912Sgonzo 2432252912Sgonzo switch (xfer_type) { 2433252912Sgonzo case UE_CONTROL: 2434252912Sgonzo temp.transfer_type |= MUSB2_MASK_TI_PROTO_CTRL; 2435252912Sgonzo break; 2436252912Sgonzo case UE_ISOCHRONOUS: 2437252912Sgonzo temp.transfer_type |= MUSB2_MASK_TI_PROTO_ISOC; 2438252912Sgonzo break; 2439252912Sgonzo case UE_BULK: 2440252912Sgonzo temp.transfer_type |= MUSB2_MASK_TI_PROTO_BULK; 2441252912Sgonzo break; 2442252912Sgonzo case UE_INTERRUPT: 2443252912Sgonzo temp.transfer_type |= MUSB2_MASK_TI_PROTO_INTR; 2444252912Sgonzo break; 2445252912Sgonzo default: 2446252912Sgonzo DPRINTFN(-1, "Invalid USB transfer type: %d\n", 2447252912Sgonzo xfer_type); 2448252912Sgonzo break; 2449252912Sgonzo } 2450252912Sgonzo 2451252912Sgonzo temp.transfer_type |= ep_no; 2452252912Sgonzo td->toggle = xfer->endpoint->toggle_next; 2453252912Sgonzo } 2454252912Sgonzo 2455184610Salfred /* check if we should prepend a setup message */ 2456184610Salfred 2457184610Salfred if (xfer->flags_int.control_xfr) { 2458184610Salfred if (xfer->flags_int.control_hdr) { 2459184610Salfred 2460252912Sgonzo if (xfer->flags_int.usb_mode == USB_MODE_DEVICE) 2461252912Sgonzo temp.func = &musbotg_dev_ctrl_setup_rx; 2462252912Sgonzo else 2463252912Sgonzo temp.func = &musbotg_host_ctrl_setup_tx; 2464252912Sgonzo 2465184610Salfred temp.len = xfer->frlengths[0]; 2466184610Salfred temp.pc = xfer->frbuffers + 0; 2467184610Salfred temp.short_pkt = temp.len ? 1 : 0; 2468184610Salfred 2469184610Salfred musbotg_setup_standard_chain_sub(&temp); 2470184610Salfred } 2471184610Salfred x = 1; 2472184610Salfred } else { 2473184610Salfred x = 0; 2474184610Salfred } 2475184610Salfred 2476257043Shselasky tx = 0; 2477257043Shselasky 2478184610Salfred if (x != xfer->nframes) { 2479252912Sgonzo if (xfer->endpointno & UE_DIR_IN) 2480252912Sgonzo tx = 1; 2481252912Sgonzo 2482252912Sgonzo if (xfer->flags_int.usb_mode == USB_MODE_HOST) { 2483252912Sgonzo tx = !tx; 2484252912Sgonzo 2485252912Sgonzo if (tx) { 2486252912Sgonzo if (xfer->flags_int.control_xfr) 2487252912Sgonzo temp.func = &musbotg_host_ctrl_data_tx; 2488252912Sgonzo else 2489252912Sgonzo temp.func = &musbotg_host_data_tx; 2490252912Sgonzo } else { 2491252912Sgonzo if (xfer->flags_int.control_xfr) 2492252912Sgonzo temp.func = &musbotg_host_ctrl_data_rx; 2493252912Sgonzo else 2494252912Sgonzo temp.func = &musbotg_host_data_rx; 2495252912Sgonzo } 2496252912Sgonzo 2497184610Salfred } else { 2498252912Sgonzo if (tx) { 2499252912Sgonzo if (xfer->flags_int.control_xfr) 2500252912Sgonzo temp.func = &musbotg_dev_ctrl_data_tx; 2501252912Sgonzo else 2502252912Sgonzo temp.func = &musbotg_dev_data_tx; 2503252912Sgonzo } else { 2504252912Sgonzo if (xfer->flags_int.control_xfr) 2505252912Sgonzo temp.func = &musbotg_dev_ctrl_data_rx; 2506252912Sgonzo else 2507252912Sgonzo temp.func = &musbotg_dev_data_rx; 2508252912Sgonzo } 2509184610Salfred } 2510184610Salfred 2511184610Salfred /* setup "pc" pointer */ 2512184610Salfred temp.pc = xfer->frbuffers + x; 2513184610Salfred } 2514184610Salfred while (x != xfer->nframes) { 2515184610Salfred 2516184610Salfred /* DATA0 / DATA1 message */ 2517184610Salfred 2518184610Salfred temp.len = xfer->frlengths[x]; 2519184610Salfred 2520184610Salfred x++; 2521184610Salfred 2522184610Salfred if (x == xfer->nframes) { 2523190183Sthompsa if (xfer->flags_int.control_xfr) { 2524190183Sthompsa if (xfer->flags_int.control_act) { 2525190183Sthompsa temp.setup_alt_next = 0; 2526190183Sthompsa } 2527190183Sthompsa } else { 2528190183Sthompsa temp.setup_alt_next = 0; 2529190183Sthompsa } 2530184610Salfred } 2531184610Salfred if (temp.len == 0) { 2532184610Salfred 2533184610Salfred /* make sure that we send an USB packet */ 2534184610Salfred 2535184610Salfred temp.short_pkt = 0; 2536184610Salfred 2537184610Salfred } else { 2538184610Salfred 2539257043Shselasky if (xfer->flags_int.isochronous_xfr) { 2540257043Shselasky /* isochronous data transfer */ 2541257043Shselasky /* don't force short */ 2542257043Shselasky temp.short_pkt = 1; 2543257043Shselasky } else { 2544257043Shselasky /* regular data transfer */ 2545257043Shselasky temp.short_pkt = (xfer->flags.force_short_xfer ? 0 : 1); 2546257043Shselasky } 2547184610Salfred } 2548184610Salfred 2549184610Salfred musbotg_setup_standard_chain_sub(&temp); 2550184610Salfred 2551184610Salfred if (xfer->flags_int.isochronous_xfr) { 2552184610Salfred temp.offset += temp.len; 2553184610Salfred } else { 2554184610Salfred /* get next Page Cache pointer */ 2555184610Salfred temp.pc = xfer->frbuffers + x; 2556184610Salfred } 2557184610Salfred } 2558184610Salfred 2559190183Sthompsa /* check for control transfer */ 2560190183Sthompsa if (xfer->flags_int.control_xfr) { 2561184610Salfred 2562190183Sthompsa /* always setup a valid "pc" pointer for status and sync */ 2563190183Sthompsa temp.pc = xfer->frbuffers + 0; 2564184610Salfred temp.len = 0; 2565184610Salfred temp.short_pkt = 0; 2566190183Sthompsa temp.setup_alt_next = 0; 2567184610Salfred 2568190183Sthompsa /* check if we should append a status stage */ 2569190183Sthompsa if (!xfer->flags_int.control_act) { 2570190183Sthompsa /* 2571190183Sthompsa * Send a DATA1 message and invert the current 2572190183Sthompsa * endpoint direction. 2573190183Sthompsa */ 2574252912Sgonzo if (sc->sc_mode == MUSB2_DEVICE_MODE) 2575252912Sgonzo temp.func = &musbotg_dev_ctrl_status; 2576252912Sgonzo else { 2577252912Sgonzo if (xfer->endpointno & UE_DIR_IN) 2578252912Sgonzo temp.func = musbotg_host_ctrl_status_tx; 2579252912Sgonzo else 2580252912Sgonzo temp.func = musbotg_host_ctrl_status_rx; 2581252912Sgonzo } 2582190183Sthompsa musbotg_setup_standard_chain_sub(&temp); 2583190183Sthompsa } 2584184610Salfred } 2585184610Salfred /* must have at least one frame! */ 2586184610Salfred td = temp.td; 2587184610Salfred xfer->td_transfer_last = td; 2588184610Salfred} 2589184610Salfred 2590184610Salfredstatic void 2591184610Salfredmusbotg_timeout(void *arg) 2592184610Salfred{ 2593192984Sthompsa struct usb_xfer *xfer = arg; 2594184610Salfred 2595184610Salfred DPRINTFN(1, "xfer=%p\n", xfer); 2596184610Salfred 2597187173Sthompsa USB_BUS_LOCK_ASSERT(xfer->xroot->bus, MA_OWNED); 2598184610Salfred 2599184610Salfred /* transfer is transferred */ 2600184610Salfred musbotg_device_done(xfer, USB_ERR_TIMEOUT); 2601184610Salfred} 2602184610Salfred 2603184610Salfredstatic void 2604252912Sgonzomusbotg_ep_int_set(struct musbotg_softc *sc, int channel, int on) 2605184610Salfred{ 2606184610Salfred uint16_t temp; 2607184610Salfred 2608184610Salfred /* 2609184610Salfred * Only enable the endpoint interrupt when we are 2610184610Salfred * actually waiting for data, hence we are dealing 2611184610Salfred * with level triggered interrupts ! 2612184610Salfred */ 2613252912Sgonzo DPRINTFN(1, "ep_no=%d, on=%d\n", channel, on); 2614252912Sgonzo 2615252912Sgonzo if (channel == -1) 2616252912Sgonzo return; 2617252912Sgonzo 2618252912Sgonzo if (channel == 0) { 2619184610Salfred temp = MUSB2_READ_2(sc, MUSB2_REG_INTTXE); 2620184610Salfred if (on) 2621184610Salfred temp |= MUSB2_MASK_EPINT(0); 2622184610Salfred else 2623184610Salfred temp &= ~MUSB2_MASK_EPINT(0); 2624184610Salfred 2625184610Salfred MUSB2_WRITE_2(sc, MUSB2_REG_INTTXE, temp); 2626184610Salfred } else { 2627252912Sgonzo temp = MUSB2_READ_2(sc, MUSB2_REG_INTRXE); 2628252912Sgonzo if (on) 2629252912Sgonzo temp |= MUSB2_MASK_EPINT(channel); 2630252912Sgonzo else 2631252912Sgonzo temp &= ~MUSB2_MASK_EPINT(channel); 2632252912Sgonzo MUSB2_WRITE_2(sc, MUSB2_REG_INTRXE, temp); 2633184610Salfred 2634252912Sgonzo temp = MUSB2_READ_2(sc, MUSB2_REG_INTTXE); 2635252912Sgonzo if (on) 2636252912Sgonzo temp |= MUSB2_MASK_EPINT(channel); 2637252912Sgonzo else 2638252912Sgonzo temp &= ~MUSB2_MASK_EPINT(channel); 2639252912Sgonzo MUSB2_WRITE_2(sc, MUSB2_REG_INTTXE, temp); 2640184610Salfred } 2641252912Sgonzo 2642252912Sgonzo if (sc->sc_ep_int_set) 2643252912Sgonzo sc->sc_ep_int_set(sc, channel, on); 2644184610Salfred} 2645184610Salfred 2646184610Salfredstatic void 2647192984Sthompsamusbotg_start_standard_chain(struct usb_xfer *xfer) 2648184610Salfred{ 2649184610Salfred DPRINTFN(8, "\n"); 2650184610Salfred 2651184610Salfred /* poll one time */ 2652184610Salfred if (musbotg_xfer_do_fifo(xfer)) { 2653184610Salfred 2654184610Salfred DPRINTFN(14, "enabled interrupts on endpoint\n"); 2655184610Salfred 2656184610Salfred /* put transfer on interrupt queue */ 2657194228Sthompsa usbd_transfer_enqueue(&xfer->xroot->bus->intr_q, xfer); 2658184610Salfred 2659184610Salfred /* start timeout, if any */ 2660184610Salfred if (xfer->timeout != 0) { 2661194228Sthompsa usbd_transfer_timeout_ms(xfer, 2662184610Salfred &musbotg_timeout, xfer->timeout); 2663184610Salfred } 2664184610Salfred } 2665184610Salfred} 2666184610Salfred 2667184610Salfredstatic void 2668190735Sthompsamusbotg_root_intr(struct musbotg_softc *sc) 2669184610Salfred{ 2670184610Salfred DPRINTFN(8, "\n"); 2671184610Salfred 2672184824Sthompsa USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED); 2673184610Salfred 2674184610Salfred /* set port bit */ 2675184610Salfred sc->sc_hub_idata[0] = 0x02; /* we only have one port */ 2676184610Salfred 2677190735Sthompsa uhub_root_intr(&sc->sc_bus, sc->sc_hub_idata, 2678190735Sthompsa sizeof(sc->sc_hub_idata)); 2679184610Salfred} 2680184610Salfred 2681193045Sthompsastatic usb_error_t 2682192984Sthompsamusbotg_standard_done_sub(struct usb_xfer *xfer) 2683184610Salfred{ 2684184610Salfred struct musbotg_td *td; 2685184610Salfred uint32_t len; 2686184610Salfred uint8_t error; 2687184610Salfred 2688184610Salfred DPRINTFN(8, "\n"); 2689184610Salfred 2690184610Salfred td = xfer->td_transfer_cache; 2691184610Salfred 2692184610Salfred do { 2693184610Salfred len = td->remainder; 2694184610Salfred 2695252912Sgonzo xfer->endpoint->toggle_next = td->toggle; 2696252912Sgonzo 2697184610Salfred if (xfer->aframes != xfer->nframes) { 2698184610Salfred /* 2699184610Salfred * Verify the length and subtract 2700184610Salfred * the remainder from "frlengths[]": 2701184610Salfred */ 2702184610Salfred if (len > xfer->frlengths[xfer->aframes]) { 2703184610Salfred td->error = 1; 2704184610Salfred } else { 2705184610Salfred xfer->frlengths[xfer->aframes] -= len; 2706184610Salfred } 2707184610Salfred } 2708184610Salfred /* Check for transfer error */ 2709184610Salfred if (td->error) { 2710184610Salfred /* the transfer is finished */ 2711184610Salfred error = 1; 2712184610Salfred td = NULL; 2713184610Salfred break; 2714184610Salfred } 2715184610Salfred /* Check for short transfer */ 2716184610Salfred if (len > 0) { 2717184610Salfred if (xfer->flags_int.short_frames_ok) { 2718184610Salfred /* follow alt next */ 2719184610Salfred if (td->alt_next) { 2720184610Salfred td = td->obj_next; 2721184610Salfred } else { 2722184610Salfred td = NULL; 2723184610Salfred } 2724184610Salfred } else { 2725184610Salfred /* the transfer is finished */ 2726184610Salfred td = NULL; 2727184610Salfred } 2728184610Salfred error = 0; 2729184610Salfred break; 2730184610Salfred } 2731184610Salfred td = td->obj_next; 2732184610Salfred 2733184610Salfred /* this USB frame is complete */ 2734184610Salfred error = 0; 2735184610Salfred break; 2736184610Salfred 2737184610Salfred } while (0); 2738184610Salfred 2739184610Salfred /* update transfer cache */ 2740184610Salfred 2741184610Salfred xfer->td_transfer_cache = td; 2742184610Salfred 2743184610Salfred return (error ? 2744184610Salfred USB_ERR_STALLED : USB_ERR_NORMAL_COMPLETION); 2745184610Salfred} 2746184610Salfred 2747184610Salfredstatic void 2748192984Sthompsamusbotg_standard_done(struct usb_xfer *xfer) 2749184610Salfred{ 2750193045Sthompsa usb_error_t err = 0; 2751184610Salfred 2752193644Sthompsa DPRINTFN(12, "xfer=%p endpoint=%p transfer done\n", 2753193644Sthompsa xfer, xfer->endpoint); 2754184610Salfred 2755184610Salfred /* reset scanner */ 2756184610Salfred 2757184610Salfred xfer->td_transfer_cache = xfer->td_transfer_first; 2758184610Salfred 2759184610Salfred if (xfer->flags_int.control_xfr) { 2760184610Salfred 2761184610Salfred if (xfer->flags_int.control_hdr) { 2762184610Salfred 2763184610Salfred err = musbotg_standard_done_sub(xfer); 2764184610Salfred } 2765184610Salfred xfer->aframes = 1; 2766184610Salfred 2767184610Salfred if (xfer->td_transfer_cache == NULL) { 2768184610Salfred goto done; 2769184610Salfred } 2770184610Salfred } 2771184610Salfred while (xfer->aframes != xfer->nframes) { 2772184610Salfred 2773184610Salfred err = musbotg_standard_done_sub(xfer); 2774184610Salfred xfer->aframes++; 2775184610Salfred 2776184610Salfred if (xfer->td_transfer_cache == NULL) { 2777184610Salfred goto done; 2778184610Salfred } 2779184610Salfred } 2780184610Salfred 2781184610Salfred if (xfer->flags_int.control_xfr && 2782184610Salfred !xfer->flags_int.control_act) { 2783184610Salfred 2784184610Salfred err = musbotg_standard_done_sub(xfer); 2785184610Salfred } 2786184610Salfreddone: 2787184610Salfred musbotg_device_done(xfer, err); 2788184610Salfred} 2789184610Salfred 2790184610Salfred/*------------------------------------------------------------------------* 2791184610Salfred * musbotg_device_done 2792184610Salfred * 2793184610Salfred * NOTE: this function can be called more than one time on the 2794184610Salfred * same USB transfer! 2795184610Salfred *------------------------------------------------------------------------*/ 2796184610Salfredstatic void 2797193045Sthompsamusbotg_device_done(struct usb_xfer *xfer, usb_error_t error) 2798184610Salfred{ 2799252912Sgonzo struct musbotg_td *td; 2800252912Sgonzo struct musbotg_softc *sc; 2801252912Sgonzo 2802187173Sthompsa USB_BUS_LOCK_ASSERT(xfer->xroot->bus, MA_OWNED); 2803184610Salfred 2804252912Sgonzo DPRINTFN(1, "xfer=%p, endpoint=%p, error=%d\n", 2805193644Sthompsa xfer, xfer->endpoint, error); 2806184610Salfred 2807252912Sgonzo DPRINTFN(14, "disabled interrupts on endpoint\n"); 2808184610Salfred 2809252912Sgonzo sc = MUSBOTG_BUS2SC(xfer->xroot->bus); 2810252912Sgonzo td = xfer->td_transfer_cache; 2811184610Salfred 2812252912Sgonzo if (td && (td->channel != -1)) 2813252912Sgonzo musbotg_channel_free(sc, td); 2814252912Sgonzo 2815184610Salfred /* dequeue transfer and start next transfer */ 2816194228Sthompsa usbd_transfer_done(xfer, error); 2817184610Salfred} 2818184610Salfred 2819184610Salfredstatic void 2820239214Shselaskymusbotg_xfer_stall(struct usb_xfer *xfer) 2821239214Shselasky{ 2822239214Shselasky musbotg_device_done(xfer, USB_ERR_STALLED); 2823239214Shselasky} 2824239214Shselasky 2825239214Shselaskystatic void 2826239214Shselaskymusbotg_set_stall(struct usb_device *udev, 2827195121Sthompsa struct usb_endpoint *ep, uint8_t *did_stall) 2828184610Salfred{ 2829184610Salfred struct musbotg_softc *sc; 2830184610Salfred uint8_t ep_no; 2831184610Salfred 2832184824Sthompsa USB_BUS_LOCK_ASSERT(udev->bus, MA_OWNED); 2833184610Salfred 2834193644Sthompsa DPRINTFN(4, "endpoint=%p\n", ep); 2835184610Salfred 2836184610Salfred /* set FORCESTALL */ 2837184610Salfred sc = MUSBOTG_BUS2SC(udev->bus); 2838184610Salfred 2839193644Sthompsa ep_no = (ep->edesc->bEndpointAddress & UE_ADDR); 2840184610Salfred 2841184610Salfred /* select endpoint */ 2842184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_EPINDEX, ep_no); 2843184610Salfred 2844193644Sthompsa if (ep->edesc->bEndpointAddress & UE_DIR_IN) { 2845184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 2846184610Salfred MUSB2_MASK_CSRL_TXSENDSTALL); 2847184610Salfred } else { 2848184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_RXCSRL, 2849184610Salfred MUSB2_MASK_CSRL_RXSENDSTALL); 2850184610Salfred } 2851184610Salfred} 2852184610Salfred 2853184610Salfredstatic void 2854184610Salfredmusbotg_clear_stall_sub(struct musbotg_softc *sc, uint16_t wMaxPacket, 2855184610Salfred uint8_t ep_no, uint8_t ep_type, uint8_t ep_dir) 2856184610Salfred{ 2857184610Salfred uint16_t mps; 2858184610Salfred uint16_t temp; 2859184610Salfred uint8_t csr; 2860184610Salfred 2861184610Salfred if (ep_type == UE_CONTROL) { 2862184610Salfred /* clearing stall is not needed */ 2863184610Salfred return; 2864184610Salfred } 2865184610Salfred /* select endpoint */ 2866184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_EPINDEX, ep_no); 2867184610Salfred 2868184610Salfred /* compute max frame size */ 2869184610Salfred mps = wMaxPacket & 0x7FF; 2870184610Salfred switch ((wMaxPacket >> 11) & 3) { 2871184610Salfred case 1: 2872184610Salfred mps *= 2; 2873184610Salfred break; 2874184610Salfred case 2: 2875184610Salfred mps *= 3; 2876184610Salfred break; 2877184610Salfred default: 2878184610Salfred break; 2879184610Salfred } 2880184610Salfred 2881184610Salfred if (ep_dir == UE_DIR_IN) { 2882184610Salfred 2883184610Salfred temp = 0; 2884184610Salfred 2885184610Salfred /* Configure endpoint */ 2886184610Salfred switch (ep_type) { 2887184610Salfred case UE_INTERRUPT: 2888199676Sthompsa MUSB2_WRITE_2(sc, MUSB2_REG_TXMAXP, wMaxPacket); 2889184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRH, 2890184610Salfred MUSB2_MASK_CSRH_TXMODE | temp); 2891184610Salfred break; 2892184610Salfred case UE_ISOCHRONOUS: 2893199676Sthompsa MUSB2_WRITE_2(sc, MUSB2_REG_TXMAXP, wMaxPacket); 2894184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRH, 2895184610Salfred MUSB2_MASK_CSRH_TXMODE | 2896184610Salfred MUSB2_MASK_CSRH_TXISO | temp); 2897184610Salfred break; 2898184610Salfred case UE_BULK: 2899199676Sthompsa MUSB2_WRITE_2(sc, MUSB2_REG_TXMAXP, wMaxPacket); 2900184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRH, 2901184610Salfred MUSB2_MASK_CSRH_TXMODE | temp); 2902184610Salfred break; 2903184610Salfred default: 2904184610Salfred break; 2905184610Salfred } 2906184610Salfred 2907184610Salfred /* Need to flush twice in case of double bufring */ 2908184610Salfred csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL); 2909184610Salfred if (csr & MUSB2_MASK_CSRL_TXFIFONEMPTY) { 2910184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 2911184610Salfred MUSB2_MASK_CSRL_TXFFLUSH); 2912184610Salfred csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL); 2913184610Salfred if (csr & MUSB2_MASK_CSRL_TXFIFONEMPTY) { 2914184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 2915184610Salfred MUSB2_MASK_CSRL_TXFFLUSH); 2916184610Salfred csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL); 2917184610Salfred } 2918184610Salfred } 2919184610Salfred /* reset data toggle */ 2920184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 2921184610Salfred MUSB2_MASK_CSRL_TXDT_CLR); 2922184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 0); 2923184610Salfred csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL); 2924184610Salfred 2925184610Salfred /* set double/single buffering */ 2926184610Salfred temp = MUSB2_READ_2(sc, MUSB2_REG_TXDBDIS); 2927184610Salfred if (mps <= (sc->sc_hw_ep_profile[ep_no]. 2928184610Salfred max_in_frame_size / 2)) { 2929184610Salfred /* double buffer */ 2930184610Salfred temp &= ~(1 << ep_no); 2931184610Salfred } else { 2932184610Salfred /* single buffer */ 2933184610Salfred temp |= (1 << ep_no); 2934184610Salfred } 2935184610Salfred MUSB2_WRITE_2(sc, MUSB2_REG_TXDBDIS, temp); 2936184610Salfred 2937184610Salfred /* clear sent stall */ 2938184610Salfred if (csr & MUSB2_MASK_CSRL_TXSENTSTALL) { 2939184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 0); 2940184610Salfred csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL); 2941184610Salfred } 2942184610Salfred } else { 2943184610Salfred 2944184610Salfred temp = 0; 2945184610Salfred 2946184610Salfred /* Configure endpoint */ 2947184610Salfred switch (ep_type) { 2948184610Salfred case UE_INTERRUPT: 2949199676Sthompsa MUSB2_WRITE_2(sc, MUSB2_REG_RXMAXP, wMaxPacket); 2950184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_RXCSRH, 2951184610Salfred MUSB2_MASK_CSRH_RXNYET | temp); 2952184610Salfred break; 2953184610Salfred case UE_ISOCHRONOUS: 2954199676Sthompsa MUSB2_WRITE_2(sc, MUSB2_REG_RXMAXP, wMaxPacket); 2955184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_RXCSRH, 2956184610Salfred MUSB2_MASK_CSRH_RXNYET | 2957184610Salfred MUSB2_MASK_CSRH_RXISO | temp); 2958184610Salfred break; 2959184610Salfred case UE_BULK: 2960199676Sthompsa MUSB2_WRITE_2(sc, MUSB2_REG_RXMAXP, wMaxPacket); 2961184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_RXCSRH, temp); 2962184610Salfred break; 2963184610Salfred default: 2964184610Salfred break; 2965184610Salfred } 2966184610Salfred 2967184610Salfred /* Need to flush twice in case of double bufring */ 2968184610Salfred csr = MUSB2_READ_1(sc, MUSB2_REG_RXCSRL); 2969184610Salfred if (csr & MUSB2_MASK_CSRL_RXPKTRDY) { 2970184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_RXCSRL, 2971184610Salfred MUSB2_MASK_CSRL_RXFFLUSH); 2972184610Salfred csr = MUSB2_READ_1(sc, MUSB2_REG_RXCSRL); 2973184610Salfred if (csr & MUSB2_MASK_CSRL_RXPKTRDY) { 2974184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_RXCSRL, 2975184610Salfred MUSB2_MASK_CSRL_RXFFLUSH); 2976184610Salfred csr = MUSB2_READ_1(sc, MUSB2_REG_RXCSRL); 2977184610Salfred } 2978184610Salfred } 2979184610Salfred /* reset data toggle */ 2980184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_RXCSRL, 2981184610Salfred MUSB2_MASK_CSRL_RXDT_CLR); 2982184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_RXCSRL, 0); 2983184610Salfred csr = MUSB2_READ_1(sc, MUSB2_REG_RXCSRL); 2984184610Salfred 2985184610Salfred /* set double/single buffering */ 2986184610Salfred temp = MUSB2_READ_2(sc, MUSB2_REG_RXDBDIS); 2987184610Salfred if (mps <= (sc->sc_hw_ep_profile[ep_no]. 2988184610Salfred max_out_frame_size / 2)) { 2989184610Salfred /* double buffer */ 2990184610Salfred temp &= ~(1 << ep_no); 2991184610Salfred } else { 2992184610Salfred /* single buffer */ 2993184610Salfred temp |= (1 << ep_no); 2994184610Salfred } 2995184610Salfred MUSB2_WRITE_2(sc, MUSB2_REG_RXDBDIS, temp); 2996184610Salfred 2997184610Salfred /* clear sent stall */ 2998184610Salfred if (csr & MUSB2_MASK_CSRL_RXSENTSTALL) { 2999184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_RXCSRL, 0); 3000184610Salfred } 3001184610Salfred } 3002184610Salfred} 3003184610Salfred 3004184610Salfredstatic void 3005193644Sthompsamusbotg_clear_stall(struct usb_device *udev, struct usb_endpoint *ep) 3006184610Salfred{ 3007184610Salfred struct musbotg_softc *sc; 3008192984Sthompsa struct usb_endpoint_descriptor *ed; 3009184610Salfred 3010193644Sthompsa DPRINTFN(4, "endpoint=%p\n", ep); 3011184610Salfred 3012184824Sthompsa USB_BUS_LOCK_ASSERT(udev->bus, MA_OWNED); 3013184610Salfred 3014184610Salfred /* check mode */ 3015192499Sthompsa if (udev->flags.usb_mode != USB_MODE_DEVICE) { 3016184610Salfred /* not supported */ 3017184610Salfred return; 3018184610Salfred } 3019184610Salfred /* get softc */ 3020184610Salfred sc = MUSBOTG_BUS2SC(udev->bus); 3021184610Salfred 3022184610Salfred /* get endpoint descriptor */ 3023193644Sthompsa ed = ep->edesc; 3024184610Salfred 3025184610Salfred /* reset endpoint */ 3026184610Salfred musbotg_clear_stall_sub(sc, 3027184610Salfred UGETW(ed->wMaxPacketSize), 3028184610Salfred (ed->bEndpointAddress & UE_ADDR), 3029184610Salfred (ed->bmAttributes & UE_XFERTYPE), 3030184610Salfred (ed->bEndpointAddress & (UE_DIR_IN | UE_DIR_OUT))); 3031184610Salfred} 3032184610Salfred 3033193045Sthompsausb_error_t 3034184610Salfredmusbotg_init(struct musbotg_softc *sc) 3035184610Salfred{ 3036192984Sthompsa struct usb_hw_ep_profile *pf; 3037199676Sthompsa uint16_t offset; 3038184610Salfred uint8_t nrx; 3039184610Salfred uint8_t ntx; 3040184610Salfred uint8_t temp; 3041184610Salfred uint8_t fsize; 3042184610Salfred uint8_t frx; 3043184610Salfred uint8_t ftx; 3044199676Sthompsa uint8_t dynfifo; 3045184610Salfred 3046184610Salfred DPRINTFN(1, "start\n"); 3047184610Salfred 3048184610Salfred /* set up the bus structure */ 3049184610Salfred sc->sc_bus.usbrev = USB_REV_2_0; 3050184610Salfred sc->sc_bus.methods = &musbotg_bus_methods; 3051184610Salfred 3052184824Sthompsa USB_BUS_LOCK(&sc->sc_bus); 3053184610Salfred 3054184610Salfred /* turn on clocks */ 3055184610Salfred 3056184610Salfred if (sc->sc_clocks_on) { 3057184610Salfred (sc->sc_clocks_on) (sc->sc_clocks_arg); 3058184610Salfred } 3059252912Sgonzo 3060184610Salfred /* wait a little for things to stabilise */ 3061194228Sthompsa usb_pause_mtx(&sc->sc_bus.bus_mtx, hz / 1000); 3062184610Salfred 3063184610Salfred /* disable all interrupts */ 3064184610Salfred 3065252912Sgonzo temp = MUSB2_READ_1(sc, MUSB2_REG_DEVCTL); 3066252912Sgonzo DPRINTF("pre-DEVCTL=0x%02x\n", temp); 3067252912Sgonzo 3068184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_INTUSBE, 0); 3069184610Salfred MUSB2_WRITE_2(sc, MUSB2_REG_INTTXE, 0); 3070184610Salfred MUSB2_WRITE_2(sc, MUSB2_REG_INTRXE, 0); 3071184610Salfred 3072184610Salfred /* disable pullup */ 3073184610Salfred 3074184610Salfred musbotg_pull_common(sc, 0); 3075184610Salfred 3076184610Salfred /* wait a little bit (10ms) */ 3077194228Sthompsa usb_pause_mtx(&sc->sc_bus.bus_mtx, hz / 100); 3078184610Salfred 3079252912Sgonzo 3080184610Salfred /* disable double packet buffering */ 3081184610Salfred MUSB2_WRITE_2(sc, MUSB2_REG_RXDBDIS, 0xFFFF); 3082184610Salfred MUSB2_WRITE_2(sc, MUSB2_REG_TXDBDIS, 0xFFFF); 3083184610Salfred 3084184610Salfred /* enable HighSpeed and ISO Update flags */ 3085184610Salfred 3086184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_POWER, 3087184610Salfred MUSB2_MASK_HSENAB | MUSB2_MASK_ISOUPD); 3088184610Salfred 3089252912Sgonzo if (sc->sc_mode == MUSB2_DEVICE_MODE) { 3090252912Sgonzo /* clear Session bit, if set */ 3091252912Sgonzo temp = MUSB2_READ_1(sc, MUSB2_REG_DEVCTL); 3092252912Sgonzo temp &= ~MUSB2_MASK_SESS; 3093252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_DEVCTL, temp); 3094252912Sgonzo } else { 3095252912Sgonzo /* Enter session for Host mode */ 3096252912Sgonzo temp = MUSB2_READ_1(sc, MUSB2_REG_DEVCTL); 3097252912Sgonzo temp |= MUSB2_MASK_SESS; 3098252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_DEVCTL, temp); 3099252912Sgonzo } 3100184610Salfred 3101252912Sgonzo /* wait a little for things to stabilise */ 3102252912Sgonzo usb_pause_mtx(&sc->sc_bus.bus_mtx, hz / 10); 3103184610Salfred 3104184610Salfred DPRINTF("DEVCTL=0x%02x\n", temp); 3105184610Salfred 3106184610Salfred /* disable testmode */ 3107184610Salfred 3108184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_TESTMODE, 0); 3109184610Salfred 3110184610Salfred /* set default value */ 3111184610Salfred 3112184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_MISC, 0); 3113184610Salfred 3114184610Salfred /* select endpoint index 0 */ 3115184610Salfred 3116184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_EPINDEX, 0); 3117184610Salfred 3118184610Salfred /* read out number of endpoints */ 3119184610Salfred 3120184610Salfred nrx = 3121184610Salfred (MUSB2_READ_1(sc, MUSB2_REG_EPINFO) / 16); 3122184610Salfred 3123184610Salfred ntx = 3124184610Salfred (MUSB2_READ_1(sc, MUSB2_REG_EPINFO) % 16); 3125184610Salfred 3126184610Salfred /* these numbers exclude the control endpoint */ 3127184610Salfred 3128184610Salfred DPRINTFN(2, "RX/TX endpoints: %u/%u\n", nrx, ntx); 3129184610Salfred 3130184610Salfred sc->sc_ep_max = (nrx > ntx) ? nrx : ntx; 3131184610Salfred if (sc->sc_ep_max == 0) { 3132184610Salfred DPRINTFN(2, "ERROR: Looks like the clocks are off!\n"); 3133184610Salfred } 3134184610Salfred /* read out configuration data */ 3135184610Salfred 3136184610Salfred sc->sc_conf_data = MUSB2_READ_1(sc, MUSB2_REG_CONFDATA); 3137184610Salfred 3138184610Salfred DPRINTFN(2, "Config Data: 0x%02x\n", 3139184610Salfred sc->sc_conf_data); 3140184610Salfred 3141199676Sthompsa dynfifo = (sc->sc_conf_data & MUSB2_MASK_CD_DYNFIFOSZ) ? 1 : 0; 3142199676Sthompsa 3143199676Sthompsa if (dynfifo) { 3144199816Sthompsa device_printf(sc->sc_bus.bdev, "Dynamic FIFO sizing detected, " 3145199816Sthompsa "assuming 16Kbytes of FIFO RAM\n"); 3146199676Sthompsa } 3147199676Sthompsa 3148184610Salfred DPRINTFN(2, "HW version: 0x%04x\n", 3149184610Salfred MUSB2_READ_1(sc, MUSB2_REG_HWVERS)); 3150184610Salfred 3151184610Salfred /* initialise endpoint profiles */ 3152184610Salfred 3153199676Sthompsa offset = 0; 3154199676Sthompsa 3155184610Salfred for (temp = 1; temp <= sc->sc_ep_max; temp++) { 3156184610Salfred pf = sc->sc_hw_ep_profile + temp; 3157184610Salfred 3158184610Salfred /* select endpoint */ 3159184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_EPINDEX, temp); 3160184610Salfred 3161184610Salfred fsize = MUSB2_READ_1(sc, MUSB2_REG_FSIZE); 3162201758Smbr frx = (fsize & MUSB2_MASK_RX_FSIZE) / 16; 3163184610Salfred ftx = (fsize & MUSB2_MASK_TX_FSIZE); 3164184610Salfred 3165199676Sthompsa DPRINTF("Endpoint %u FIFO size: IN=%u, OUT=%u, DYN=%d\n", 3166199676Sthompsa temp, ftx, frx, dynfifo); 3167184610Salfred 3168199676Sthompsa if (dynfifo) { 3169199676Sthompsa if (frx && (temp <= nrx)) { 3170257043Shselasky if (temp == 1) { 3171257043Shselasky frx = 12; /* 4K */ 3172257043Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_RXFIFOSZ, 3173257043Shselasky MUSB2_VAL_FIFOSZ_4096 | 3174257043Shselasky MUSB2_MASK_FIFODB); 3175257043Shselasky } else if (temp < 8) { 3176199676Sthompsa frx = 10; /* 1K */ 3177199676Sthompsa MUSB2_WRITE_1(sc, MUSB2_REG_RXFIFOSZ, 3178199676Sthompsa MUSB2_VAL_FIFOSZ_512 | 3179199676Sthompsa MUSB2_MASK_FIFODB); 3180199676Sthompsa } else { 3181199676Sthompsa frx = 7; /* 128 bytes */ 3182199676Sthompsa MUSB2_WRITE_1(sc, MUSB2_REG_RXFIFOSZ, 3183199676Sthompsa MUSB2_VAL_FIFOSZ_128); 3184199676Sthompsa } 3185199676Sthompsa 3186199676Sthompsa MUSB2_WRITE_2(sc, MUSB2_REG_RXFIFOADD, 3187199676Sthompsa offset >> 3); 3188199676Sthompsa 3189199676Sthompsa offset += (1 << frx); 3190199676Sthompsa } 3191199676Sthompsa if (ftx && (temp <= ntx)) { 3192257043Shselasky if (temp == 1) { 3193257043Shselasky ftx = 12; /* 4K */ 3194257043Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_TXFIFOSZ, 3195257043Shselasky MUSB2_VAL_FIFOSZ_4096 | 3196257043Shselasky MUSB2_MASK_FIFODB); 3197257043Shselasky } else if (temp < 8) { 3198199676Sthompsa ftx = 10; /* 1K */ 3199199676Sthompsa MUSB2_WRITE_1(sc, MUSB2_REG_TXFIFOSZ, 3200199676Sthompsa MUSB2_VAL_FIFOSZ_512 | 3201199676Sthompsa MUSB2_MASK_FIFODB); 3202199676Sthompsa } else { 3203199676Sthompsa ftx = 7; /* 128 bytes */ 3204199676Sthompsa MUSB2_WRITE_1(sc, MUSB2_REG_TXFIFOSZ, 3205199676Sthompsa MUSB2_VAL_FIFOSZ_128); 3206199676Sthompsa } 3207199676Sthompsa 3208199676Sthompsa MUSB2_WRITE_2(sc, MUSB2_REG_TXFIFOADD, 3209199676Sthompsa offset >> 3); 3210199676Sthompsa 3211199676Sthompsa offset += (1 << ftx); 3212199676Sthompsa } 3213199676Sthompsa } 3214199676Sthompsa 3215184610Salfred if (frx && ftx && (temp <= nrx) && (temp <= ntx)) { 3216184610Salfred pf->max_in_frame_size = 1 << ftx; 3217184610Salfred pf->max_out_frame_size = 1 << frx; 3218184610Salfred pf->is_simplex = 0; /* duplex */ 3219184610Salfred pf->support_multi_buffer = 1; 3220184610Salfred pf->support_bulk = 1; 3221184610Salfred pf->support_interrupt = 1; 3222184610Salfred pf->support_isochronous = 1; 3223184610Salfred pf->support_in = 1; 3224184610Salfred pf->support_out = 1; 3225184610Salfred } else if (frx && (temp <= nrx)) { 3226184610Salfred pf->max_out_frame_size = 1 << frx; 3227184610Salfred pf->is_simplex = 1; /* simplex */ 3228184610Salfred pf->support_multi_buffer = 1; 3229184610Salfred pf->support_bulk = 1; 3230184610Salfred pf->support_interrupt = 1; 3231184610Salfred pf->support_isochronous = 1; 3232184610Salfred pf->support_out = 1; 3233184610Salfred } else if (ftx && (temp <= ntx)) { 3234184610Salfred pf->max_in_frame_size = 1 << ftx; 3235184610Salfred pf->is_simplex = 1; /* simplex */ 3236184610Salfred pf->support_multi_buffer = 1; 3237184610Salfred pf->support_bulk = 1; 3238184610Salfred pf->support_interrupt = 1; 3239184610Salfred pf->support_isochronous = 1; 3240184610Salfred pf->support_in = 1; 3241184610Salfred } 3242184610Salfred } 3243184610Salfred 3244199676Sthompsa DPRINTFN(2, "Dynamic FIFO size = %d bytes\n", offset); 3245199676Sthompsa 3246184610Salfred /* turn on default interrupts */ 3247184610Salfred 3248252912Sgonzo if (sc->sc_mode == MUSB2_HOST_MODE) 3249252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_INTUSBE, 0xff); 3250252912Sgonzo else 3251252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_INTUSBE, 3252252912Sgonzo MUSB2_MASK_IRESET); 3253184610Salfred 3254184610Salfred musbotg_clocks_off(sc); 3255184610Salfred 3256184824Sthompsa USB_BUS_UNLOCK(&sc->sc_bus); 3257184610Salfred 3258184610Salfred /* catch any lost interrupts */ 3259184610Salfred 3260184610Salfred musbotg_do_poll(&sc->sc_bus); 3261184610Salfred 3262184610Salfred return (0); /* success */ 3263184610Salfred} 3264184610Salfred 3265184610Salfredvoid 3266184610Salfredmusbotg_uninit(struct musbotg_softc *sc) 3267184610Salfred{ 3268184824Sthompsa USB_BUS_LOCK(&sc->sc_bus); 3269184610Salfred 3270184610Salfred /* disable all interrupts */ 3271184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_INTUSBE, 0); 3272184610Salfred MUSB2_WRITE_2(sc, MUSB2_REG_INTTXE, 0); 3273184610Salfred MUSB2_WRITE_2(sc, MUSB2_REG_INTRXE, 0); 3274184610Salfred 3275184610Salfred sc->sc_flags.port_powered = 0; 3276184610Salfred sc->sc_flags.status_vbus = 0; 3277184610Salfred sc->sc_flags.status_bus_reset = 0; 3278184610Salfred sc->sc_flags.status_suspend = 0; 3279184610Salfred sc->sc_flags.change_suspend = 0; 3280184610Salfred sc->sc_flags.change_connect = 1; 3281184610Salfred 3282184610Salfred musbotg_pull_down(sc); 3283184610Salfred musbotg_clocks_off(sc); 3284184824Sthompsa USB_BUS_UNLOCK(&sc->sc_bus); 3285184610Salfred} 3286184610Salfred 3287228483Shselaskystatic void 3288184610Salfredmusbotg_suspend(struct musbotg_softc *sc) 3289184610Salfred{ 3290228483Shselasky /* TODO */ 3291184610Salfred} 3292184610Salfred 3293228483Shselaskystatic void 3294184610Salfredmusbotg_resume(struct musbotg_softc *sc) 3295184610Salfred{ 3296228483Shselasky /* TODO */ 3297184610Salfred} 3298184610Salfred 3299184610Salfredstatic void 3300192984Sthompsamusbotg_do_poll(struct usb_bus *bus) 3301184610Salfred{ 3302184610Salfred struct musbotg_softc *sc = MUSBOTG_BUS2SC(bus); 3303184610Salfred 3304184824Sthompsa USB_BUS_LOCK(&sc->sc_bus); 3305184610Salfred musbotg_interrupt_poll(sc); 3306184824Sthompsa USB_BUS_UNLOCK(&sc->sc_bus); 3307184610Salfred} 3308184610Salfred 3309184610Salfred/*------------------------------------------------------------------------* 3310184610Salfred * musbotg bulk support 3311184610Salfred *------------------------------------------------------------------------*/ 3312184610Salfredstatic void 3313192984Sthompsamusbotg_device_bulk_open(struct usb_xfer *xfer) 3314184610Salfred{ 3315184610Salfred return; 3316184610Salfred} 3317184610Salfred 3318184610Salfredstatic void 3319192984Sthompsamusbotg_device_bulk_close(struct usb_xfer *xfer) 3320184610Salfred{ 3321184610Salfred musbotg_device_done(xfer, USB_ERR_CANCELLED); 3322184610Salfred} 3323184610Salfred 3324184610Salfredstatic void 3325192984Sthompsamusbotg_device_bulk_enter(struct usb_xfer *xfer) 3326184610Salfred{ 3327184610Salfred return; 3328184610Salfred} 3329184610Salfred 3330184610Salfredstatic void 3331192984Sthompsamusbotg_device_bulk_start(struct usb_xfer *xfer) 3332184610Salfred{ 3333184610Salfred /* setup TDs */ 3334184610Salfred musbotg_setup_standard_chain(xfer); 3335184610Salfred musbotg_start_standard_chain(xfer); 3336184610Salfred} 3337184610Salfred 3338192984Sthompsastruct usb_pipe_methods musbotg_device_bulk_methods = 3339184610Salfred{ 3340184610Salfred .open = musbotg_device_bulk_open, 3341184610Salfred .close = musbotg_device_bulk_close, 3342184610Salfred .enter = musbotg_device_bulk_enter, 3343184610Salfred .start = musbotg_device_bulk_start, 3344184610Salfred}; 3345184610Salfred 3346184610Salfred/*------------------------------------------------------------------------* 3347184610Salfred * musbotg control support 3348184610Salfred *------------------------------------------------------------------------*/ 3349184610Salfredstatic void 3350192984Sthompsamusbotg_device_ctrl_open(struct usb_xfer *xfer) 3351184610Salfred{ 3352184610Salfred return; 3353184610Salfred} 3354184610Salfred 3355184610Salfredstatic void 3356192984Sthompsamusbotg_device_ctrl_close(struct usb_xfer *xfer) 3357184610Salfred{ 3358184610Salfred musbotg_device_done(xfer, USB_ERR_CANCELLED); 3359184610Salfred} 3360184610Salfred 3361184610Salfredstatic void 3362192984Sthompsamusbotg_device_ctrl_enter(struct usb_xfer *xfer) 3363184610Salfred{ 3364184610Salfred return; 3365184610Salfred} 3366184610Salfred 3367184610Salfredstatic void 3368192984Sthompsamusbotg_device_ctrl_start(struct usb_xfer *xfer) 3369184610Salfred{ 3370184610Salfred /* setup TDs */ 3371184610Salfred musbotg_setup_standard_chain(xfer); 3372184610Salfred musbotg_start_standard_chain(xfer); 3373184610Salfred} 3374184610Salfred 3375192984Sthompsastruct usb_pipe_methods musbotg_device_ctrl_methods = 3376184610Salfred{ 3377184610Salfred .open = musbotg_device_ctrl_open, 3378184610Salfred .close = musbotg_device_ctrl_close, 3379184610Salfred .enter = musbotg_device_ctrl_enter, 3380184610Salfred .start = musbotg_device_ctrl_start, 3381184610Salfred}; 3382184610Salfred 3383184610Salfred/*------------------------------------------------------------------------* 3384184610Salfred * musbotg interrupt support 3385184610Salfred *------------------------------------------------------------------------*/ 3386184610Salfredstatic void 3387192984Sthompsamusbotg_device_intr_open(struct usb_xfer *xfer) 3388184610Salfred{ 3389184610Salfred return; 3390184610Salfred} 3391184610Salfred 3392184610Salfredstatic void 3393192984Sthompsamusbotg_device_intr_close(struct usb_xfer *xfer) 3394184610Salfred{ 3395184610Salfred musbotg_device_done(xfer, USB_ERR_CANCELLED); 3396184610Salfred} 3397184610Salfred 3398184610Salfredstatic void 3399192984Sthompsamusbotg_device_intr_enter(struct usb_xfer *xfer) 3400184610Salfred{ 3401184610Salfred return; 3402184610Salfred} 3403184610Salfred 3404184610Salfredstatic void 3405192984Sthompsamusbotg_device_intr_start(struct usb_xfer *xfer) 3406184610Salfred{ 3407184610Salfred /* setup TDs */ 3408184610Salfred musbotg_setup_standard_chain(xfer); 3409184610Salfred musbotg_start_standard_chain(xfer); 3410184610Salfred} 3411184610Salfred 3412192984Sthompsastruct usb_pipe_methods musbotg_device_intr_methods = 3413184610Salfred{ 3414184610Salfred .open = musbotg_device_intr_open, 3415184610Salfred .close = musbotg_device_intr_close, 3416184610Salfred .enter = musbotg_device_intr_enter, 3417184610Salfred .start = musbotg_device_intr_start, 3418184610Salfred}; 3419184610Salfred 3420184610Salfred/*------------------------------------------------------------------------* 3421184610Salfred * musbotg full speed isochronous support 3422184610Salfred *------------------------------------------------------------------------*/ 3423184610Salfredstatic void 3424192984Sthompsamusbotg_device_isoc_open(struct usb_xfer *xfer) 3425184610Salfred{ 3426184610Salfred return; 3427184610Salfred} 3428184610Salfred 3429184610Salfredstatic void 3430192984Sthompsamusbotg_device_isoc_close(struct usb_xfer *xfer) 3431184610Salfred{ 3432184610Salfred musbotg_device_done(xfer, USB_ERR_CANCELLED); 3433184610Salfred} 3434184610Salfred 3435184610Salfredstatic void 3436192984Sthompsamusbotg_device_isoc_enter(struct usb_xfer *xfer) 3437184610Salfred{ 3438187173Sthompsa struct musbotg_softc *sc = MUSBOTG_BUS2SC(xfer->xroot->bus); 3439184610Salfred uint32_t temp; 3440184610Salfred uint32_t nframes; 3441184610Salfred uint32_t fs_frames; 3442184610Salfred 3443184610Salfred DPRINTFN(5, "xfer=%p next=%d nframes=%d\n", 3444193644Sthompsa xfer, xfer->endpoint->isoc_next, xfer->nframes); 3445184610Salfred 3446184610Salfred /* get the current frame index */ 3447184610Salfred 3448184610Salfred nframes = MUSB2_READ_2(sc, MUSB2_REG_FRAME); 3449184610Salfred 3450184610Salfred /* 3451184610Salfred * check if the frame index is within the window where the frames 3452184610Salfred * will be inserted 3453184610Salfred */ 3454193644Sthompsa temp = (nframes - xfer->endpoint->isoc_next) & MUSB2_MASK_FRAME; 3455184610Salfred 3456194228Sthompsa if (usbd_get_speed(xfer->xroot->udev) == USB_SPEED_HIGH) { 3457184610Salfred fs_frames = (xfer->nframes + 7) / 8; 3458184610Salfred } else { 3459184610Salfred fs_frames = xfer->nframes; 3460184610Salfred } 3461184610Salfred 3462193644Sthompsa if ((xfer->endpoint->is_synced == 0) || 3463184610Salfred (temp < fs_frames)) { 3464184610Salfred /* 3465184610Salfred * If there is data underflow or the pipe queue is 3466184610Salfred * empty we schedule the transfer a few frames ahead 3467184610Salfred * of the current frame position. Else two isochronous 3468184610Salfred * transfers might overlap. 3469184610Salfred */ 3470193644Sthompsa xfer->endpoint->isoc_next = (nframes + 3) & MUSB2_MASK_FRAME; 3471193644Sthompsa xfer->endpoint->is_synced = 1; 3472193644Sthompsa DPRINTFN(2, "start next=%d\n", xfer->endpoint->isoc_next); 3473184610Salfred } 3474184610Salfred /* 3475184610Salfred * compute how many milliseconds the insertion is ahead of the 3476184610Salfred * current frame position: 3477184610Salfred */ 3478193644Sthompsa temp = (xfer->endpoint->isoc_next - nframes) & MUSB2_MASK_FRAME; 3479184610Salfred 3480184610Salfred /* 3481184610Salfred * pre-compute when the isochronous transfer will be finished: 3482184610Salfred */ 3483184610Salfred xfer->isoc_time_complete = 3484194228Sthompsa usb_isoc_time_expand(&sc->sc_bus, nframes) + temp + 3485184610Salfred fs_frames; 3486184610Salfred 3487184610Salfred /* compute frame number for next insertion */ 3488193644Sthompsa xfer->endpoint->isoc_next += fs_frames; 3489184610Salfred 3490184610Salfred /* setup TDs */ 3491184610Salfred musbotg_setup_standard_chain(xfer); 3492184610Salfred} 3493184610Salfred 3494184610Salfredstatic void 3495192984Sthompsamusbotg_device_isoc_start(struct usb_xfer *xfer) 3496184610Salfred{ 3497184610Salfred /* start TD chain */ 3498184610Salfred musbotg_start_standard_chain(xfer); 3499184610Salfred} 3500184610Salfred 3501192984Sthompsastruct usb_pipe_methods musbotg_device_isoc_methods = 3502184610Salfred{ 3503184610Salfred .open = musbotg_device_isoc_open, 3504184610Salfred .close = musbotg_device_isoc_close, 3505184610Salfred .enter = musbotg_device_isoc_enter, 3506184610Salfred .start = musbotg_device_isoc_start, 3507184610Salfred}; 3508184610Salfred 3509184610Salfred/*------------------------------------------------------------------------* 3510184610Salfred * musbotg root control support 3511184610Salfred *------------------------------------------------------------------------* 3512190735Sthompsa * Simulate a hardware HUB by handling all the necessary requests. 3513184610Salfred *------------------------------------------------------------------------*/ 3514184610Salfred 3515192984Sthompsastatic const struct usb_device_descriptor musbotg_devd = { 3516192984Sthompsa .bLength = sizeof(struct usb_device_descriptor), 3517184610Salfred .bDescriptorType = UDESC_DEVICE, 3518184610Salfred .bcdUSB = {0x00, 0x02}, 3519184610Salfred .bDeviceClass = UDCLASS_HUB, 3520184610Salfred .bDeviceSubClass = UDSUBCLASS_HUB, 3521184610Salfred .bDeviceProtocol = UDPROTO_HSHUBSTT, 3522184610Salfred .bMaxPacketSize = 64, 3523184610Salfred .bcdDevice = {0x00, 0x01}, 3524184610Salfred .iManufacturer = 1, 3525184610Salfred .iProduct = 2, 3526184610Salfred .bNumConfigurations = 1, 3527184610Salfred}; 3528184610Salfred 3529192984Sthompsastatic const struct usb_device_qualifier musbotg_odevd = { 3530192984Sthompsa .bLength = sizeof(struct usb_device_qualifier), 3531184610Salfred .bDescriptorType = UDESC_DEVICE_QUALIFIER, 3532184610Salfred .bcdUSB = {0x00, 0x02}, 3533184610Salfred .bDeviceClass = UDCLASS_HUB, 3534184610Salfred .bDeviceSubClass = UDSUBCLASS_HUB, 3535184610Salfred .bDeviceProtocol = UDPROTO_FSHUB, 3536184610Salfred .bMaxPacketSize0 = 0, 3537184610Salfred .bNumConfigurations = 0, 3538184610Salfred}; 3539184610Salfred 3540184610Salfredstatic const struct musbotg_config_desc musbotg_confd = { 3541184610Salfred .confd = { 3542192984Sthompsa .bLength = sizeof(struct usb_config_descriptor), 3543184610Salfred .bDescriptorType = UDESC_CONFIG, 3544184610Salfred .wTotalLength[0] = sizeof(musbotg_confd), 3545184610Salfred .bNumInterface = 1, 3546184610Salfred .bConfigurationValue = 1, 3547184610Salfred .iConfiguration = 0, 3548184610Salfred .bmAttributes = UC_SELF_POWERED, 3549184610Salfred .bMaxPower = 0, 3550184610Salfred }, 3551184610Salfred .ifcd = { 3552192984Sthompsa .bLength = sizeof(struct usb_interface_descriptor), 3553184610Salfred .bDescriptorType = UDESC_INTERFACE, 3554184610Salfred .bNumEndpoints = 1, 3555184610Salfred .bInterfaceClass = UICLASS_HUB, 3556184610Salfred .bInterfaceSubClass = UISUBCLASS_HUB, 3557213802Shselasky .bInterfaceProtocol = 0, 3558184610Salfred }, 3559184610Salfred .endpd = { 3560192984Sthompsa .bLength = sizeof(struct usb_endpoint_descriptor), 3561184610Salfred .bDescriptorType = UDESC_ENDPOINT, 3562184610Salfred .bEndpointAddress = (UE_DIR_IN | MUSBOTG_INTR_ENDPT), 3563184610Salfred .bmAttributes = UE_INTERRUPT, 3564184610Salfred .wMaxPacketSize[0] = 8, 3565184610Salfred .bInterval = 255, 3566184610Salfred }, 3567184610Salfred}; 3568184610Salfred 3569233774Shselasky#define HSETW(ptr, val) ptr = { (uint8_t)(val), (uint8_t)((val) >> 8) } 3570233774Shselasky 3571192984Sthompsastatic const struct usb_hub_descriptor_min musbotg_hubd = { 3572184610Salfred .bDescLength = sizeof(musbotg_hubd), 3573184610Salfred .bDescriptorType = UDESC_HUB, 3574184610Salfred .bNbrPorts = 1, 3575233774Shselasky HSETW(.wHubCharacteristics, (UHD_PWR_NO_SWITCH | UHD_OC_INDIVIDUAL)), 3576184610Salfred .bPwrOn2PwrGood = 50, 3577184610Salfred .bHubContrCurrent = 0, 3578184610Salfred .DeviceRemovable = {0}, /* port is removable */ 3579184610Salfred}; 3580184610Salfred 3581184610Salfred#define STRING_VENDOR \ 3582246125Shselasky "M\0e\0n\0t\0o\0r\0 \0G\0r\0a\0p\0h\0i\0c\0s" 3583184610Salfred 3584184610Salfred#define STRING_PRODUCT \ 3585246125Shselasky "O\0T\0G\0 \0R\0o\0o\0t\0 \0H\0U\0B" 3586184610Salfred 3587184610SalfredUSB_MAKE_STRING_DESC(STRING_VENDOR, musbotg_vendor); 3588184610SalfredUSB_MAKE_STRING_DESC(STRING_PRODUCT, musbotg_product); 3589184610Salfred 3590193045Sthompsastatic usb_error_t 3591192984Sthompsamusbotg_roothub_exec(struct usb_device *udev, 3592192984Sthompsa struct usb_device_request *req, const void **pptr, uint16_t *plength) 3593184610Salfred{ 3594191402Sthompsa struct musbotg_softc *sc = MUSBOTG_BUS2SC(udev->bus); 3595191402Sthompsa const void *ptr; 3596191402Sthompsa uint16_t len; 3597184610Salfred uint16_t value; 3598184610Salfred uint16_t index; 3599252912Sgonzo uint8_t reg; 3600193045Sthompsa usb_error_t err; 3601184610Salfred 3602184824Sthompsa USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED); 3603184610Salfred 3604184610Salfred /* buffer reset */ 3605191402Sthompsa ptr = (const void *)&sc->sc_hub_temp; 3606191402Sthompsa len = 0; 3607191402Sthompsa err = 0; 3608184610Salfred 3609191402Sthompsa value = UGETW(req->wValue); 3610191402Sthompsa index = UGETW(req->wIndex); 3611184610Salfred 3612184610Salfred /* demultiplex the control request */ 3613184610Salfred 3614191402Sthompsa switch (req->bmRequestType) { 3615184610Salfred case UT_READ_DEVICE: 3616191402Sthompsa switch (req->bRequest) { 3617184610Salfred case UR_GET_DESCRIPTOR: 3618184610Salfred goto tr_handle_get_descriptor; 3619184610Salfred case UR_GET_CONFIG: 3620184610Salfred goto tr_handle_get_config; 3621184610Salfred case UR_GET_STATUS: 3622184610Salfred goto tr_handle_get_status; 3623184610Salfred default: 3624184610Salfred goto tr_stalled; 3625184610Salfred } 3626184610Salfred break; 3627184610Salfred 3628184610Salfred case UT_WRITE_DEVICE: 3629191402Sthompsa switch (req->bRequest) { 3630184610Salfred case UR_SET_ADDRESS: 3631184610Salfred goto tr_handle_set_address; 3632184610Salfred case UR_SET_CONFIG: 3633184610Salfred goto tr_handle_set_config; 3634184610Salfred case UR_CLEAR_FEATURE: 3635184610Salfred goto tr_valid; /* nop */ 3636184610Salfred case UR_SET_DESCRIPTOR: 3637184610Salfred goto tr_valid; /* nop */ 3638184610Salfred case UR_SET_FEATURE: 3639184610Salfred default: 3640184610Salfred goto tr_stalled; 3641184610Salfred } 3642184610Salfred break; 3643184610Salfred 3644184610Salfred case UT_WRITE_ENDPOINT: 3645191402Sthompsa switch (req->bRequest) { 3646184610Salfred case UR_CLEAR_FEATURE: 3647191402Sthompsa switch (UGETW(req->wValue)) { 3648184610Salfred case UF_ENDPOINT_HALT: 3649184610Salfred goto tr_handle_clear_halt; 3650184610Salfred case UF_DEVICE_REMOTE_WAKEUP: 3651184610Salfred goto tr_handle_clear_wakeup; 3652184610Salfred default: 3653184610Salfred goto tr_stalled; 3654184610Salfred } 3655184610Salfred break; 3656184610Salfred case UR_SET_FEATURE: 3657191402Sthompsa switch (UGETW(req->wValue)) { 3658184610Salfred case UF_ENDPOINT_HALT: 3659184610Salfred goto tr_handle_set_halt; 3660184610Salfred case UF_DEVICE_REMOTE_WAKEUP: 3661184610Salfred goto tr_handle_set_wakeup; 3662184610Salfred default: 3663184610Salfred goto tr_stalled; 3664184610Salfred } 3665184610Salfred break; 3666184610Salfred case UR_SYNCH_FRAME: 3667184610Salfred goto tr_valid; /* nop */ 3668184610Salfred default: 3669184610Salfred goto tr_stalled; 3670184610Salfred } 3671184610Salfred break; 3672184610Salfred 3673184610Salfred case UT_READ_ENDPOINT: 3674191402Sthompsa switch (req->bRequest) { 3675184610Salfred case UR_GET_STATUS: 3676184610Salfred goto tr_handle_get_ep_status; 3677184610Salfred default: 3678184610Salfred goto tr_stalled; 3679184610Salfred } 3680184610Salfred break; 3681184610Salfred 3682184610Salfred case UT_WRITE_INTERFACE: 3683191402Sthompsa switch (req->bRequest) { 3684184610Salfred case UR_SET_INTERFACE: 3685184610Salfred goto tr_handle_set_interface; 3686184610Salfred case UR_CLEAR_FEATURE: 3687184610Salfred goto tr_valid; /* nop */ 3688184610Salfred case UR_SET_FEATURE: 3689184610Salfred default: 3690184610Salfred goto tr_stalled; 3691184610Salfred } 3692184610Salfred break; 3693184610Salfred 3694184610Salfred case UT_READ_INTERFACE: 3695191402Sthompsa switch (req->bRequest) { 3696184610Salfred case UR_GET_INTERFACE: 3697184610Salfred goto tr_handle_get_interface; 3698184610Salfred case UR_GET_STATUS: 3699184610Salfred goto tr_handle_get_iface_status; 3700184610Salfred default: 3701184610Salfred goto tr_stalled; 3702184610Salfred } 3703184610Salfred break; 3704184610Salfred 3705184610Salfred case UT_WRITE_CLASS_INTERFACE: 3706184610Salfred case UT_WRITE_VENDOR_INTERFACE: 3707184610Salfred /* XXX forward */ 3708184610Salfred break; 3709184610Salfred 3710184610Salfred case UT_READ_CLASS_INTERFACE: 3711184610Salfred case UT_READ_VENDOR_INTERFACE: 3712184610Salfred /* XXX forward */ 3713184610Salfred break; 3714184610Salfred 3715184610Salfred case UT_WRITE_CLASS_DEVICE: 3716191402Sthompsa switch (req->bRequest) { 3717184610Salfred case UR_CLEAR_FEATURE: 3718184610Salfred goto tr_valid; 3719184610Salfred case UR_SET_DESCRIPTOR: 3720184610Salfred case UR_SET_FEATURE: 3721184610Salfred break; 3722184610Salfred default: 3723184610Salfred goto tr_stalled; 3724184610Salfred } 3725184610Salfred break; 3726184610Salfred 3727184610Salfred case UT_WRITE_CLASS_OTHER: 3728191402Sthompsa switch (req->bRequest) { 3729184610Salfred case UR_CLEAR_FEATURE: 3730184610Salfred goto tr_handle_clear_port_feature; 3731184610Salfred case UR_SET_FEATURE: 3732184610Salfred goto tr_handle_set_port_feature; 3733184610Salfred case UR_CLEAR_TT_BUFFER: 3734184610Salfred case UR_RESET_TT: 3735184610Salfred case UR_STOP_TT: 3736184610Salfred goto tr_valid; 3737184610Salfred 3738184610Salfred default: 3739184610Salfred goto tr_stalled; 3740184610Salfred } 3741184610Salfred break; 3742184610Salfred 3743184610Salfred case UT_READ_CLASS_OTHER: 3744191402Sthompsa switch (req->bRequest) { 3745184610Salfred case UR_GET_TT_STATE: 3746184610Salfred goto tr_handle_get_tt_state; 3747184610Salfred case UR_GET_STATUS: 3748184610Salfred goto tr_handle_get_port_status; 3749184610Salfred default: 3750184610Salfred goto tr_stalled; 3751184610Salfred } 3752184610Salfred break; 3753184610Salfred 3754184610Salfred case UT_READ_CLASS_DEVICE: 3755191402Sthompsa switch (req->bRequest) { 3756184610Salfred case UR_GET_DESCRIPTOR: 3757184610Salfred goto tr_handle_get_class_descriptor; 3758184610Salfred case UR_GET_STATUS: 3759184610Salfred goto tr_handle_get_class_status; 3760184610Salfred 3761184610Salfred default: 3762184610Salfred goto tr_stalled; 3763184610Salfred } 3764184610Salfred break; 3765184610Salfred default: 3766184610Salfred goto tr_stalled; 3767184610Salfred } 3768184610Salfred goto tr_valid; 3769184610Salfred 3770184610Salfredtr_handle_get_descriptor: 3771184610Salfred switch (value >> 8) { 3772184610Salfred case UDESC_DEVICE: 3773184610Salfred if (value & 0xff) { 3774184610Salfred goto tr_stalled; 3775184610Salfred } 3776191402Sthompsa len = sizeof(musbotg_devd); 3777191402Sthompsa ptr = (const void *)&musbotg_devd; 3778184610Salfred goto tr_valid; 3779184610Salfred case UDESC_CONFIG: 3780184610Salfred if (value & 0xff) { 3781184610Salfred goto tr_stalled; 3782184610Salfred } 3783191402Sthompsa len = sizeof(musbotg_confd); 3784191402Sthompsa ptr = (const void *)&musbotg_confd; 3785184610Salfred goto tr_valid; 3786184610Salfred case UDESC_STRING: 3787184610Salfred switch (value & 0xff) { 3788184610Salfred case 0: /* Language table */ 3789246123Shselasky len = sizeof(usb_string_lang_en); 3790246123Shselasky ptr = (const void *)&usb_string_lang_en; 3791184610Salfred goto tr_valid; 3792184610Salfred 3793184610Salfred case 1: /* Vendor */ 3794191402Sthompsa len = sizeof(musbotg_vendor); 3795191402Sthompsa ptr = (const void *)&musbotg_vendor; 3796184610Salfred goto tr_valid; 3797184610Salfred 3798184610Salfred case 2: /* Product */ 3799191402Sthompsa len = sizeof(musbotg_product); 3800191402Sthompsa ptr = (const void *)&musbotg_product; 3801184610Salfred goto tr_valid; 3802184610Salfred default: 3803184610Salfred break; 3804184610Salfred } 3805184610Salfred break; 3806184610Salfred default: 3807184610Salfred goto tr_stalled; 3808184610Salfred } 3809184610Salfred goto tr_stalled; 3810184610Salfred 3811184610Salfredtr_handle_get_config: 3812191402Sthompsa len = 1; 3813184610Salfred sc->sc_hub_temp.wValue[0] = sc->sc_conf; 3814184610Salfred goto tr_valid; 3815184610Salfred 3816184610Salfredtr_handle_get_status: 3817191402Sthompsa len = 2; 3818184610Salfred USETW(sc->sc_hub_temp.wValue, UDS_SELF_POWERED); 3819184610Salfred goto tr_valid; 3820184610Salfred 3821184610Salfredtr_handle_set_address: 3822184610Salfred if (value & 0xFF00) { 3823184610Salfred goto tr_stalled; 3824184610Salfred } 3825184610Salfred sc->sc_rt_addr = value; 3826184610Salfred goto tr_valid; 3827184610Salfred 3828184610Salfredtr_handle_set_config: 3829184610Salfred if (value >= 2) { 3830184610Salfred goto tr_stalled; 3831184610Salfred } 3832184610Salfred sc->sc_conf = value; 3833184610Salfred goto tr_valid; 3834184610Salfred 3835184610Salfredtr_handle_get_interface: 3836191402Sthompsa len = 1; 3837184610Salfred sc->sc_hub_temp.wValue[0] = 0; 3838184610Salfred goto tr_valid; 3839184610Salfred 3840184610Salfredtr_handle_get_tt_state: 3841184610Salfredtr_handle_get_class_status: 3842184610Salfredtr_handle_get_iface_status: 3843184610Salfredtr_handle_get_ep_status: 3844191402Sthompsa len = 2; 3845184610Salfred USETW(sc->sc_hub_temp.wValue, 0); 3846184610Salfred goto tr_valid; 3847184610Salfred 3848184610Salfredtr_handle_set_halt: 3849184610Salfredtr_handle_set_interface: 3850184610Salfredtr_handle_set_wakeup: 3851184610Salfredtr_handle_clear_wakeup: 3852184610Salfredtr_handle_clear_halt: 3853184610Salfred goto tr_valid; 3854184610Salfred 3855184610Salfredtr_handle_clear_port_feature: 3856184610Salfred if (index != 1) { 3857184610Salfred goto tr_stalled; 3858184610Salfred } 3859184610Salfred DPRINTFN(8, "UR_CLEAR_PORT_FEATURE on port %d\n", index); 3860184610Salfred 3861184610Salfred switch (value) { 3862184610Salfred case UHF_PORT_SUSPEND: 3863252912Sgonzo if (sc->sc_mode == MUSB2_HOST_MODE) 3864252912Sgonzo musbotg_wakeup_host(sc); 3865252912Sgonzo else 3866252912Sgonzo musbotg_wakeup_peer(sc); 3867184610Salfred break; 3868184610Salfred 3869184610Salfred case UHF_PORT_ENABLE: 3870184610Salfred sc->sc_flags.port_enabled = 0; 3871184610Salfred break; 3872184610Salfred 3873184610Salfred case UHF_C_PORT_ENABLE: 3874252912Sgonzo sc->sc_flags.change_enabled = 0; 3875252912Sgonzo break; 3876252912Sgonzo 3877184610Salfred case UHF_C_PORT_OVER_CURRENT: 3878252912Sgonzo sc->sc_flags.change_over_current = 0; 3879252912Sgonzo break; 3880252912Sgonzo 3881184610Salfred case UHF_C_PORT_RESET: 3882252912Sgonzo sc->sc_flags.change_reset = 0; 3883252912Sgonzo break; 3884252912Sgonzo 3885252912Sgonzo case UHF_PORT_TEST: 3886252912Sgonzo case UHF_PORT_INDICATOR: 3887184610Salfred /* nops */ 3888184610Salfred break; 3889252912Sgonzo 3890184610Salfred case UHF_PORT_POWER: 3891184610Salfred sc->sc_flags.port_powered = 0; 3892184610Salfred musbotg_pull_down(sc); 3893184610Salfred musbotg_clocks_off(sc); 3894184610Salfred break; 3895184610Salfred case UHF_C_PORT_CONNECTION: 3896184610Salfred sc->sc_flags.change_connect = 0; 3897184610Salfred break; 3898184610Salfred case UHF_C_PORT_SUSPEND: 3899184610Salfred sc->sc_flags.change_suspend = 0; 3900184610Salfred break; 3901184610Salfred default: 3902191402Sthompsa err = USB_ERR_IOERROR; 3903184610Salfred goto done; 3904184610Salfred } 3905184610Salfred goto tr_valid; 3906184610Salfred 3907184610Salfredtr_handle_set_port_feature: 3908184610Salfred if (index != 1) { 3909184610Salfred goto tr_stalled; 3910184610Salfred } 3911184610Salfred DPRINTFN(8, "UR_SET_PORT_FEATURE\n"); 3912184610Salfred 3913184610Salfred switch (value) { 3914184610Salfred case UHF_PORT_ENABLE: 3915184610Salfred sc->sc_flags.port_enabled = 1; 3916184610Salfred break; 3917184610Salfred case UHF_PORT_SUSPEND: 3918252912Sgonzo if (sc->sc_mode == MUSB2_HOST_MODE) 3919252912Sgonzo musbotg_suspend_host(sc); 3920252912Sgonzo break; 3921252912Sgonzo 3922184610Salfred case UHF_PORT_RESET: 3923252912Sgonzo if (sc->sc_mode == MUSB2_HOST_MODE) { 3924252912Sgonzo reg = MUSB2_READ_1(sc, MUSB2_REG_POWER); 3925252912Sgonzo reg |= MUSB2_MASK_RESET; 3926252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_POWER, reg); 3927252912Sgonzo 3928252912Sgonzo /* Wait for 20 msec */ 3929252912Sgonzo usb_pause_mtx(&sc->sc_bus.bus_mtx, hz / 5); 3930252912Sgonzo 3931252912Sgonzo reg = MUSB2_READ_1(sc, MUSB2_REG_POWER); 3932252912Sgonzo reg &= ~MUSB2_MASK_RESET; 3933252912Sgonzo MUSB2_WRITE_1(sc, MUSB2_REG_POWER, reg); 3934252912Sgonzo 3935252912Sgonzo /* determine line speed */ 3936252912Sgonzo reg = MUSB2_READ_1(sc, MUSB2_REG_POWER); 3937252912Sgonzo if (reg & MUSB2_MASK_HSMODE) 3938252912Sgonzo sc->sc_flags.status_high_speed = 1; 3939252912Sgonzo else 3940252912Sgonzo sc->sc_flags.status_high_speed = 0; 3941252912Sgonzo 3942252912Sgonzo sc->sc_flags.change_reset = 1; 3943252912Sgonzo } else 3944252912Sgonzo err = USB_ERR_IOERROR; 3945252912Sgonzo break; 3946252912Sgonzo 3947184610Salfred case UHF_PORT_TEST: 3948184610Salfred case UHF_PORT_INDICATOR: 3949184610Salfred /* nops */ 3950184610Salfred break; 3951184610Salfred case UHF_PORT_POWER: 3952184610Salfred sc->sc_flags.port_powered = 1; 3953184610Salfred break; 3954184610Salfred default: 3955191402Sthompsa err = USB_ERR_IOERROR; 3956184610Salfred goto done; 3957184610Salfred } 3958184610Salfred goto tr_valid; 3959184610Salfred 3960184610Salfredtr_handle_get_port_status: 3961184610Salfred 3962184610Salfred DPRINTFN(8, "UR_GET_PORT_STATUS\n"); 3963184610Salfred 3964184610Salfred if (index != 1) { 3965184610Salfred goto tr_stalled; 3966184610Salfred } 3967184610Salfred if (sc->sc_flags.status_vbus) { 3968184610Salfred musbotg_clocks_on(sc); 3969184610Salfred musbotg_pull_up(sc); 3970184610Salfred } else { 3971184610Salfred musbotg_pull_down(sc); 3972184610Salfred musbotg_clocks_off(sc); 3973184610Salfred } 3974184610Salfred 3975184610Salfred /* Select Device Side Mode */ 3976252912Sgonzo if (sc->sc_mode == MUSB2_DEVICE_MODE) 3977252912Sgonzo value = UPS_PORT_MODE_DEVICE; 3978252912Sgonzo else 3979252912Sgonzo value = 0; 3980184610Salfred 3981184610Salfred if (sc->sc_flags.status_high_speed) { 3982184610Salfred value |= UPS_HIGH_SPEED; 3983184610Salfred } 3984184610Salfred if (sc->sc_flags.port_powered) { 3985184610Salfred value |= UPS_PORT_POWER; 3986184610Salfred } 3987184610Salfred if (sc->sc_flags.port_enabled) { 3988184610Salfred value |= UPS_PORT_ENABLED; 3989184610Salfred } 3990252912Sgonzo 3991252912Sgonzo if (sc->sc_flags.port_over_current) 3992252912Sgonzo value |= UPS_OVERCURRENT_INDICATOR; 3993252912Sgonzo 3994184610Salfred if (sc->sc_flags.status_vbus && 3995184610Salfred sc->sc_flags.status_bus_reset) { 3996184610Salfred value |= UPS_CURRENT_CONNECT_STATUS; 3997184610Salfred } 3998184610Salfred if (sc->sc_flags.status_suspend) { 3999184610Salfred value |= UPS_SUSPEND; 4000184610Salfred } 4001184610Salfred USETW(sc->sc_hub_temp.ps.wPortStatus, value); 4002184610Salfred 4003184610Salfred value = 0; 4004184610Salfred 4005184610Salfred if (sc->sc_flags.change_connect) { 4006184610Salfred value |= UPS_C_CONNECT_STATUS; 4007184610Salfred 4008252912Sgonzo if (sc->sc_mode == MUSB2_DEVICE_MODE) { 4009252912Sgonzo if (sc->sc_flags.status_vbus && 4010252912Sgonzo sc->sc_flags.status_bus_reset) { 4011252912Sgonzo /* reset EP0 state */ 4012252912Sgonzo sc->sc_ep0_busy = 0; 4013252912Sgonzo sc->sc_ep0_cmd = 0; 4014252912Sgonzo } 4015184610Salfred } 4016184610Salfred } 4017252912Sgonzo if (sc->sc_flags.change_suspend) 4018184610Salfred value |= UPS_C_SUSPEND; 4019252912Sgonzo if (sc->sc_flags.change_reset) 4020252912Sgonzo value |= UPS_C_PORT_RESET; 4021252912Sgonzo if (sc->sc_flags.change_over_current) 4022252912Sgonzo value |= UPS_C_OVERCURRENT_INDICATOR; 4023252912Sgonzo 4024184610Salfred USETW(sc->sc_hub_temp.ps.wPortChange, value); 4025191402Sthompsa len = sizeof(sc->sc_hub_temp.ps); 4026184610Salfred goto tr_valid; 4027184610Salfred 4028184610Salfredtr_handle_get_class_descriptor: 4029184610Salfred if (value & 0xFF) { 4030184610Salfred goto tr_stalled; 4031184610Salfred } 4032191402Sthompsa ptr = (const void *)&musbotg_hubd; 4033191402Sthompsa len = sizeof(musbotg_hubd); 4034184610Salfred goto tr_valid; 4035184610Salfred 4036184610Salfredtr_stalled: 4037191402Sthompsa err = USB_ERR_STALLED; 4038184610Salfredtr_valid: 4039184610Salfreddone: 4040191402Sthompsa *plength = len; 4041191402Sthompsa *pptr = ptr; 4042191402Sthompsa return (err); 4043184610Salfred} 4044184610Salfred 4045184610Salfredstatic void 4046192984Sthompsamusbotg_xfer_setup(struct usb_setup_params *parm) 4047184610Salfred{ 4048184610Salfred struct musbotg_softc *sc; 4049192984Sthompsa struct usb_xfer *xfer; 4050184610Salfred void *last_obj; 4051184610Salfred uint32_t ntd; 4052184610Salfred uint32_t n; 4053184610Salfred uint8_t ep_no; 4054184610Salfred 4055184610Salfred sc = MUSBOTG_BUS2SC(parm->udev->bus); 4056184610Salfred xfer = parm->curr_xfer; 4057184610Salfred 4058184610Salfred /* 4059184610Salfred * NOTE: This driver does not use any of the parameters that 4060184610Salfred * are computed from the following values. Just set some 4061184610Salfred * reasonable dummies: 4062184610Salfred */ 4063184610Salfred parm->hc_max_packet_size = 0x400; 4064257043Shselasky parm->hc_max_frame_size = 0xc00; 4065184610Salfred 4066184610Salfred if ((parm->methods == &musbotg_device_isoc_methods) || 4067184610Salfred (parm->methods == &musbotg_device_intr_methods)) 4068184610Salfred parm->hc_max_packet_count = 3; 4069184610Salfred else 4070184610Salfred parm->hc_max_packet_count = 1; 4071184610Salfred 4072194228Sthompsa usbd_transfer_setup_sub(parm); 4073184610Salfred 4074184610Salfred /* 4075184610Salfred * compute maximum number of TDs 4076184610Salfred */ 4077184610Salfred if (parm->methods == &musbotg_device_ctrl_methods) { 4078184610Salfred 4079184610Salfred ntd = xfer->nframes + 1 /* STATUS */ + 1 /* SYNC */ ; 4080184610Salfred 4081184610Salfred } else if (parm->methods == &musbotg_device_bulk_methods) { 4082184610Salfred 4083184610Salfred ntd = xfer->nframes + 1 /* SYNC */ ; 4084184610Salfred 4085184610Salfred } else if (parm->methods == &musbotg_device_intr_methods) { 4086184610Salfred 4087184610Salfred ntd = xfer->nframes + 1 /* SYNC */ ; 4088184610Salfred 4089184610Salfred } else if (parm->methods == &musbotg_device_isoc_methods) { 4090184610Salfred 4091184610Salfred ntd = xfer->nframes + 1 /* SYNC */ ; 4092184610Salfred 4093184610Salfred } else { 4094184610Salfred 4095184610Salfred ntd = 0; 4096184610Salfred } 4097184610Salfred 4098184610Salfred /* 4099194228Sthompsa * check if "usbd_transfer_setup_sub" set an error 4100184610Salfred */ 4101184610Salfred if (parm->err) { 4102184610Salfred return; 4103184610Salfred } 4104184610Salfred /* 4105184610Salfred * allocate transfer descriptors 4106184610Salfred */ 4107184610Salfred last_obj = NULL; 4108184610Salfred 4109254828Shselasky ep_no = xfer->endpointno & UE_ADDR; 4110254828Shselasky 4111184610Salfred /* 4112254828Shselasky * Check for a valid endpoint profile in USB device mode: 4113184610Salfred */ 4114254828Shselasky if (xfer->flags_int.usb_mode == USB_MODE_DEVICE) { 4115254828Shselasky const struct usb_hw_ep_profile *pf; 4116184610Salfred 4117184610Salfred musbotg_get_hw_ep_profile(parm->udev, &pf, ep_no); 4118184610Salfred 4119184610Salfred if (pf == NULL) { 4120184610Salfred /* should not happen */ 4121184610Salfred parm->err = USB_ERR_INVAL; 4122184610Salfred return; 4123184610Salfred } 4124184610Salfred } 4125184610Salfred 4126184610Salfred /* align data */ 4127184610Salfred parm->size[0] += ((-parm->size[0]) & (USB_HOST_ALIGN - 1)); 4128184610Salfred 4129184610Salfred for (n = 0; n != ntd; n++) { 4130184610Salfred 4131184610Salfred struct musbotg_td *td; 4132184610Salfred 4133184610Salfred if (parm->buf) { 4134184610Salfred 4135184610Salfred td = USB_ADD_BYTES(parm->buf, parm->size[0]); 4136184610Salfred 4137184610Salfred /* init TD */ 4138184610Salfred td->max_frame_size = xfer->max_frame_size; 4139257043Shselasky td->reg_max_packet = xfer->max_packet_size | 4140257043Shselasky ((xfer->max_packet_count - 1) << 11); 4141184610Salfred td->ep_no = ep_no; 4142184610Salfred td->obj_next = last_obj; 4143184610Salfred 4144184610Salfred last_obj = td; 4145184610Salfred } 4146184610Salfred parm->size[0] += sizeof(*td); 4147184610Salfred } 4148184610Salfred 4149184610Salfred xfer->td_start[0] = last_obj; 4150184610Salfred} 4151184610Salfred 4152184610Salfredstatic void 4153192984Sthompsamusbotg_xfer_unsetup(struct usb_xfer *xfer) 4154184610Salfred{ 4155184610Salfred return; 4156184610Salfred} 4157184610Salfred 4158184610Salfredstatic void 4159252912Sgonzomusbotg_get_dma_delay(struct usb_device *udev, uint32_t *pus) 4160252912Sgonzo{ 4161252912Sgonzo struct musbotg_softc *sc = MUSBOTG_BUS2SC(udev->bus); 4162252912Sgonzo 4163252912Sgonzo if (sc->sc_mode == MUSB2_HOST_MODE) 4164252912Sgonzo *pus = 2000; /* microseconds */ 4165252912Sgonzo else 4166252912Sgonzo *pus = 0; 4167252912Sgonzo} 4168252912Sgonzo 4169252912Sgonzostatic void 4170193644Sthompsamusbotg_ep_init(struct usb_device *udev, struct usb_endpoint_descriptor *edesc, 4171193644Sthompsa struct usb_endpoint *ep) 4172184610Salfred{ 4173184610Salfred struct musbotg_softc *sc = MUSBOTG_BUS2SC(udev->bus); 4174184610Salfred 4175193644Sthompsa DPRINTFN(2, "endpoint=%p, addr=%d, endpt=%d, mode=%d (%d)\n", 4176193644Sthompsa ep, udev->address, 4177192499Sthompsa edesc->bEndpointAddress, udev->flags.usb_mode, 4178184610Salfred sc->sc_rt_addr); 4179184610Salfred 4180190735Sthompsa if (udev->device_index != sc->sc_rt_addr) { 4181184610Salfred switch (edesc->bmAttributes & UE_XFERTYPE) { 4182184610Salfred case UE_CONTROL: 4183193644Sthompsa ep->methods = &musbotg_device_ctrl_methods; 4184184610Salfred break; 4185184610Salfred case UE_INTERRUPT: 4186193644Sthompsa ep->methods = &musbotg_device_intr_methods; 4187184610Salfred break; 4188184610Salfred case UE_ISOCHRONOUS: 4189193644Sthompsa ep->methods = &musbotg_device_isoc_methods; 4190184610Salfred break; 4191184610Salfred case UE_BULK: 4192193644Sthompsa ep->methods = &musbotg_device_bulk_methods; 4193184610Salfred break; 4194184610Salfred default: 4195184610Salfred /* do nothing */ 4196184610Salfred break; 4197184610Salfred } 4198184610Salfred } 4199184610Salfred} 4200184610Salfred 4201228483Shselaskystatic void 4202228483Shselaskymusbotg_set_hw_power_sleep(struct usb_bus *bus, uint32_t state) 4203228483Shselasky{ 4204228483Shselasky struct musbotg_softc *sc = MUSBOTG_BUS2SC(bus); 4205228483Shselasky 4206228483Shselasky switch (state) { 4207228483Shselasky case USB_HW_POWER_SUSPEND: 4208228483Shselasky musbotg_suspend(sc); 4209228483Shselasky break; 4210228483Shselasky case USB_HW_POWER_SHUTDOWN: 4211228483Shselasky musbotg_uninit(sc); 4212228483Shselasky break; 4213228483Shselasky case USB_HW_POWER_RESUME: 4214228483Shselasky musbotg_resume(sc); 4215228483Shselasky break; 4216228483Shselasky default: 4217228483Shselasky break; 4218228483Shselasky } 4219228483Shselasky} 4220228483Shselasky 4221192984Sthompsastruct usb_bus_methods musbotg_bus_methods = 4222184610Salfred{ 4223193644Sthompsa .endpoint_init = &musbotg_ep_init, 4224252912Sgonzo .get_dma_delay = &musbotg_get_dma_delay, 4225184610Salfred .xfer_setup = &musbotg_xfer_setup, 4226184610Salfred .xfer_unsetup = &musbotg_xfer_unsetup, 4227184610Salfred .get_hw_ep_profile = &musbotg_get_hw_ep_profile, 4228239214Shselasky .xfer_stall = &musbotg_xfer_stall, 4229184610Salfred .set_stall = &musbotg_set_stall, 4230184610Salfred .clear_stall = &musbotg_clear_stall, 4231190735Sthompsa .roothub_exec = &musbotg_roothub_exec, 4232195960Salfred .xfer_poll = &musbotg_do_poll, 4233228483Shselasky .set_hw_power_sleep = &musbotg_set_hw_power_sleep, 4234184610Salfred}; 4235