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 39194677Sthompsa#include <sys/stdint.h> 40194677Sthompsa#include <sys/stddef.h> 41194677Sthompsa#include <sys/param.h> 42194677Sthompsa#include <sys/queue.h> 43194677Sthompsa#include <sys/types.h> 44194677Sthompsa#include <sys/systm.h> 45194677Sthompsa#include <sys/kernel.h> 46194677Sthompsa#include <sys/bus.h> 47194677Sthompsa#include <sys/module.h> 48194677Sthompsa#include <sys/lock.h> 49194677Sthompsa#include <sys/mutex.h> 50194677Sthompsa#include <sys/condvar.h> 51194677Sthompsa#include <sys/sysctl.h> 52194677Sthompsa#include <sys/sx.h> 53194677Sthompsa#include <sys/unistd.h> 54194677Sthompsa#include <sys/callout.h> 55194677Sthompsa#include <sys/malloc.h> 56194677Sthompsa#include <sys/priv.h> 57194677Sthompsa 58188942Sthompsa#include <dev/usb/usb.h> 59194677Sthompsa#include <dev/usb/usbdi.h> 60184610Salfred 61184610Salfred#define USB_DEBUG_VAR musbotgdebug 62184610Salfred 63188942Sthompsa#include <dev/usb/usb_core.h> 64188942Sthompsa#include <dev/usb/usb_debug.h> 65188942Sthompsa#include <dev/usb/usb_busdma.h> 66188942Sthompsa#include <dev/usb/usb_process.h> 67188942Sthompsa#include <dev/usb/usb_transfer.h> 68188942Sthompsa#include <dev/usb/usb_device.h> 69188942Sthompsa#include <dev/usb/usb_hub.h> 70188942Sthompsa#include <dev/usb/usb_util.h> 71184610Salfred 72188942Sthompsa#include <dev/usb/usb_controller.h> 73188942Sthompsa#include <dev/usb/usb_bus.h> 74188942Sthompsa#include <dev/usb/controller/musb_otg.h> 75184610Salfred 76184610Salfred#define MUSBOTG_INTR_ENDPT 1 77184610Salfred 78184610Salfred#define MUSBOTG_BUS2SC(bus) \ 79184610Salfred ((struct musbotg_softc *)(((uint8_t *)(bus)) - \ 80184610Salfred USB_P2U(&(((struct musbotg_softc *)0)->sc_bus)))) 81184610Salfred 82184610Salfred#define MUSBOTG_PC2SC(pc) \ 83190180Sthompsa MUSBOTG_BUS2SC(USB_DMATAG_TO_XROOT((pc)->tag_parent)->bus) 84184610Salfred 85194677Sthompsa#ifdef USB_DEBUG 86184610Salfredstatic int musbotgdebug = 0; 87184610Salfred 88248085Smariusstatic SYSCTL_NODE(_hw_usb, OID_AUTO, musbotg, CTLFLAG_RW, 0, "USB musbotg"); 89192502SthompsaSYSCTL_INT(_hw_usb_musbotg, OID_AUTO, debug, CTLFLAG_RW, 90184610Salfred &musbotgdebug, 0, "Debug level"); 91184610Salfred#endif 92184610Salfred 93257041Shselasky#define MAX_NAK_TO 16 94257041Shselasky 95184610Salfred/* prototypes */ 96184610Salfred 97192984Sthompsastruct usb_bus_methods musbotg_bus_methods; 98192984Sthompsastruct usb_pipe_methods musbotg_device_bulk_methods; 99192984Sthompsastruct usb_pipe_methods musbotg_device_ctrl_methods; 100192984Sthompsastruct usb_pipe_methods musbotg_device_intr_methods; 101192984Sthompsastruct usb_pipe_methods musbotg_device_isoc_methods; 102184610Salfred 103257041Shselasky/* Control transfers: Device mode */ 104257041Shselaskystatic musbotg_cmd_t musbotg_dev_ctrl_setup_rx; 105257041Shselaskystatic musbotg_cmd_t musbotg_dev_ctrl_data_rx; 106257041Shselaskystatic musbotg_cmd_t musbotg_dev_ctrl_data_tx; 107257041Shselaskystatic musbotg_cmd_t musbotg_dev_ctrl_status; 108257041Shselasky 109257041Shselasky/* Control transfers: Host mode */ 110257041Shselaskystatic musbotg_cmd_t musbotg_host_ctrl_setup_tx; 111257041Shselaskystatic musbotg_cmd_t musbotg_host_ctrl_data_rx; 112257041Shselaskystatic musbotg_cmd_t musbotg_host_ctrl_data_tx; 113257041Shselaskystatic musbotg_cmd_t musbotg_host_ctrl_status_rx; 114257041Shselaskystatic musbotg_cmd_t musbotg_host_ctrl_status_tx; 115257041Shselasky 116257041Shselasky/* Bulk, Interrupt, Isochronous: Device mode */ 117257041Shselaskystatic musbotg_cmd_t musbotg_dev_data_rx; 118257041Shselaskystatic musbotg_cmd_t musbotg_dev_data_tx; 119257041Shselasky 120257041Shselasky/* Bulk, Interrupt, Isochronous: Host mode */ 121257041Shselaskystatic musbotg_cmd_t musbotg_host_data_rx; 122257041Shselaskystatic musbotg_cmd_t musbotg_host_data_tx; 123257041Shselasky 124193045Sthompsastatic void musbotg_device_done(struct usb_xfer *, usb_error_t); 125192984Sthompsastatic void musbotg_do_poll(struct usb_bus *); 126192984Sthompsastatic void musbotg_standard_done(struct usb_xfer *); 127185948Sthompsastatic void musbotg_interrupt_poll(struct musbotg_softc *); 128190735Sthompsastatic void musbotg_root_intr(struct musbotg_softc *); 129257041Shselaskystatic int musbotg_channel_alloc(struct musbotg_softc *, struct musbotg_td *td); 130257041Shselaskystatic void musbotg_channel_free(struct musbotg_softc *, struct musbotg_td *td); 131257041Shselaskystatic void musbotg_ep_int_set(struct musbotg_softc *sc, int channel, int on); 132184610Salfred 133184610Salfred/* 134184610Salfred * Here is a configuration that the chip supports. 135184610Salfred */ 136192984Sthompsastatic const struct usb_hw_ep_profile musbotg_ep_profile[1] = { 137184610Salfred 138184610Salfred [0] = { 139184610Salfred .max_in_frame_size = 64,/* fixed */ 140184610Salfred .max_out_frame_size = 64, /* fixed */ 141184610Salfred .is_simplex = 1, 142184610Salfred .support_control = 1, 143184610Salfred } 144184610Salfred}; 145184610Salfred 146257041Shselaskystatic int 147257041Shselaskymusbotg_channel_alloc(struct musbotg_softc *sc, struct musbotg_td *td) 148257041Shselasky{ 149257041Shselasky int ch; 150257041Shselasky int ep; 151257041Shselasky 152257041Shselasky ep = td->ep_no; 153257041Shselasky 154257041Shselasky /* In device mode each EP got its own channel */ 155257041Shselasky if (sc->sc_mode == MUSB2_DEVICE_MODE) { 156257041Shselasky musbotg_ep_int_set(sc, ep, 1); 157257041Shselasky return (ep); 158257041Shselasky } 159257041Shselasky 160257041Shselasky /* 161257041Shselasky * All control transactions go through EP0 162257041Shselasky */ 163257041Shselasky if (ep == 0) { 164257041Shselasky if (sc->sc_channel_mask & (1 << 0)) 165257041Shselasky return (-1); 166257041Shselasky sc->sc_channel_mask |= (1 << 0); 167257041Shselasky musbotg_ep_int_set(sc, ep, 1); 168257041Shselasky return (0); 169257041Shselasky } 170257041Shselasky 171257041Shselasky for (ch = 1; ch < MUSB2_EP_MAX; ch++) { 172257041Shselasky if (!(sc->sc_channel_mask & (1 << ch))) { 173257041Shselasky sc->sc_channel_mask |= (1 << ch); 174257041Shselasky musbotg_ep_int_set(sc, ch, 1); 175257041Shselasky return (ch); 176257041Shselasky } 177257041Shselasky } 178257041Shselasky 179257041Shselasky DPRINTFN(-1, "No available channels. Mask: %04x\n", sc->sc_channel_mask); 180257041Shselasky 181257041Shselasky return (-1); 182257041Shselasky} 183257041Shselasky 184257041Shselaskystatic void 185257041Shselaskymusbotg_channel_free(struct musbotg_softc *sc, struct musbotg_td *td) 186257041Shselasky{ 187257041Shselasky 188257041Shselasky DPRINTFN(1, "ep_no=%d\n", td->channel); 189257041Shselasky 190257041Shselasky if (sc->sc_mode == MUSB2_DEVICE_MODE) 191257041Shselasky return; 192257041Shselasky 193257041Shselasky if (td == NULL) 194257041Shselasky return; 195257041Shselasky if (td->channel == -1) 196257041Shselasky return; 197257041Shselasky 198257041Shselasky musbotg_ep_int_set(sc, td->channel, 0); 199257041Shselasky sc->sc_channel_mask &= ~(1 << td->channel); 200257041Shselasky 201257041Shselasky td->channel = -1; 202257041Shselasky} 203257041Shselasky 204184610Salfredstatic void 205192984Sthompsamusbotg_get_hw_ep_profile(struct usb_device *udev, 206192984Sthompsa const struct usb_hw_ep_profile **ppf, uint8_t ep_addr) 207184610Salfred{ 208184610Salfred struct musbotg_softc *sc; 209184610Salfred 210184610Salfred sc = MUSBOTG_BUS2SC(udev->bus); 211184610Salfred 212184610Salfred if (ep_addr == 0) { 213184610Salfred /* control endpoint */ 214184610Salfred *ppf = musbotg_ep_profile; 215184610Salfred } else if (ep_addr <= sc->sc_ep_max) { 216184610Salfred /* other endpoints */ 217184610Salfred *ppf = sc->sc_hw_ep_profile + ep_addr; 218184610Salfred } else { 219184610Salfred *ppf = NULL; 220184610Salfred } 221184610Salfred} 222184610Salfred 223184610Salfredstatic void 224184610Salfredmusbotg_clocks_on(struct musbotg_softc *sc) 225184610Salfred{ 226184610Salfred if (sc->sc_flags.clocks_off && 227184610Salfred sc->sc_flags.port_powered) { 228184610Salfred 229184610Salfred DPRINTFN(4, "\n"); 230184610Salfred 231184610Salfred if (sc->sc_clocks_on) { 232184610Salfred (sc->sc_clocks_on) (sc->sc_clocks_arg); 233184610Salfred } 234184610Salfred sc->sc_flags.clocks_off = 0; 235184610Salfred 236184610Salfred /* XXX enable Transceiver */ 237184610Salfred } 238184610Salfred} 239184610Salfred 240184610Salfredstatic void 241184610Salfredmusbotg_clocks_off(struct musbotg_softc *sc) 242184610Salfred{ 243184610Salfred if (!sc->sc_flags.clocks_off) { 244184610Salfred 245184610Salfred DPRINTFN(4, "\n"); 246184610Salfred 247184610Salfred /* XXX disable Transceiver */ 248184610Salfred 249184610Salfred if (sc->sc_clocks_off) { 250184610Salfred (sc->sc_clocks_off) (sc->sc_clocks_arg); 251184610Salfred } 252184610Salfred sc->sc_flags.clocks_off = 1; 253184610Salfred } 254184610Salfred} 255184610Salfred 256184610Salfredstatic void 257184610Salfredmusbotg_pull_common(struct musbotg_softc *sc, uint8_t on) 258184610Salfred{ 259184610Salfred uint8_t temp; 260184610Salfred 261184610Salfred temp = MUSB2_READ_1(sc, MUSB2_REG_POWER); 262184610Salfred if (on) 263184610Salfred temp |= MUSB2_MASK_SOFTC; 264184610Salfred else 265184610Salfred temp &= ~MUSB2_MASK_SOFTC; 266184610Salfred 267184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_POWER, temp); 268184610Salfred} 269184610Salfred 270184610Salfredstatic void 271184610Salfredmusbotg_pull_up(struct musbotg_softc *sc) 272184610Salfred{ 273184610Salfred /* pullup D+, if possible */ 274184610Salfred 275184610Salfred if (!sc->sc_flags.d_pulled_up && 276184610Salfred sc->sc_flags.port_powered) { 277184610Salfred sc->sc_flags.d_pulled_up = 1; 278184610Salfred musbotg_pull_common(sc, 1); 279184610Salfred } 280184610Salfred} 281184610Salfred 282184610Salfredstatic void 283184610Salfredmusbotg_pull_down(struct musbotg_softc *sc) 284184610Salfred{ 285184610Salfred /* pulldown D+, if possible */ 286184610Salfred 287184610Salfred if (sc->sc_flags.d_pulled_up) { 288184610Salfred sc->sc_flags.d_pulled_up = 0; 289184610Salfred musbotg_pull_common(sc, 0); 290184610Salfred } 291184610Salfred} 292184610Salfred 293184610Salfredstatic void 294257041Shselaskymusbotg_suspend_host(struct musbotg_softc *sc) 295257041Shselasky{ 296257041Shselasky uint8_t temp; 297257041Shselasky 298257041Shselasky if (sc->sc_flags.status_suspend) { 299257041Shselasky return; 300257041Shselasky } 301257041Shselasky 302257041Shselasky temp = MUSB2_READ_1(sc, MUSB2_REG_POWER); 303257041Shselasky temp |= MUSB2_MASK_SUSPMODE; 304257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_POWER, temp); 305257041Shselasky sc->sc_flags.status_suspend = 1; 306257041Shselasky} 307257041Shselasky 308257041Shselaskystatic void 309257041Shselaskymusbotg_wakeup_host(struct musbotg_softc *sc) 310257041Shselasky{ 311257041Shselasky uint8_t temp; 312257041Shselasky 313257041Shselasky if (!(sc->sc_flags.status_suspend)) { 314257041Shselasky return; 315257041Shselasky } 316257041Shselasky 317257041Shselasky temp = MUSB2_READ_1(sc, MUSB2_REG_POWER); 318257041Shselasky temp &= ~MUSB2_MASK_SUSPMODE; 319257041Shselasky temp |= MUSB2_MASK_RESUME; 320257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_POWER, temp); 321257041Shselasky 322257041Shselasky /* wait 20 milliseconds */ 323257041Shselasky /* Wait for reset to complete. */ 324257041Shselasky usb_pause_mtx(&sc->sc_bus.bus_mtx, hz / 50); 325257041Shselasky 326257041Shselasky temp = MUSB2_READ_1(sc, MUSB2_REG_POWER); 327257041Shselasky temp &= ~MUSB2_MASK_RESUME; 328257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_POWER, temp); 329257041Shselasky 330257041Shselasky sc->sc_flags.status_suspend = 0; 331257041Shselasky} 332257041Shselasky 333257041Shselaskystatic void 334190735Sthompsamusbotg_wakeup_peer(struct musbotg_softc *sc) 335184610Salfred{ 336184610Salfred uint8_t temp; 337184610Salfred 338184610Salfred if (!(sc->sc_flags.status_suspend)) { 339184610Salfred return; 340184610Salfred } 341184610Salfred 342184610Salfred temp = MUSB2_READ_1(sc, MUSB2_REG_POWER); 343184610Salfred temp |= MUSB2_MASK_RESUME; 344184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_POWER, temp); 345184610Salfred 346184610Salfred /* wait 8 milliseconds */ 347188983Sthompsa /* Wait for reset to complete. */ 348194228Sthompsa usb_pause_mtx(&sc->sc_bus.bus_mtx, hz / 125); 349184610Salfred 350184610Salfred temp = MUSB2_READ_1(sc, MUSB2_REG_POWER); 351184610Salfred temp &= ~MUSB2_MASK_RESUME; 352184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_POWER, temp); 353184610Salfred} 354184610Salfred 355184610Salfredstatic void 356184610Salfredmusbotg_set_address(struct musbotg_softc *sc, uint8_t addr) 357184610Salfred{ 358184610Salfred DPRINTFN(4, "addr=%d\n", addr); 359184610Salfred addr &= 0x7F; 360184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_FADDR, addr); 361184610Salfred} 362184610Salfred 363184610Salfredstatic uint8_t 364257041Shselaskymusbotg_dev_ctrl_setup_rx(struct musbotg_td *td) 365184610Salfred{ 366184610Salfred struct musbotg_softc *sc; 367192984Sthompsa struct usb_device_request req; 368184610Salfred uint16_t count; 369184610Salfred uint8_t csr; 370184610Salfred 371184610Salfred /* get pointer to softc */ 372184610Salfred sc = MUSBOTG_PC2SC(td->pc); 373184610Salfred 374257041Shselasky if (td->channel == -1) 375257041Shselasky td->channel = musbotg_channel_alloc(sc, td); 376257041Shselasky 377257041Shselasky /* EP0 is busy, wait */ 378257041Shselasky if (td->channel == -1) 379257041Shselasky return (1); 380257041Shselasky 381257041Shselasky DPRINTFN(1, "ep_no=%d\n", td->channel); 382257041Shselasky 383184610Salfred /* select endpoint 0 */ 384184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_EPINDEX, 0); 385184610Salfred 386184610Salfred /* read out FIFO status */ 387184610Salfred csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL); 388184610Salfred 389184610Salfred DPRINTFN(4, "csr=0x%02x\n", csr); 390184610Salfred 391184610Salfred /* 392184610Salfred * NOTE: If DATAEND is set we should not call the 393184610Salfred * callback, hence the status stage is not complete. 394184610Salfred */ 395184610Salfred if (csr & MUSB2_MASK_CSR0L_DATAEND) { 396190721Sthompsa /* do not stall at this point */ 397190721Sthompsa td->did_stall = 1; 398184610Salfred /* wait for interrupt */ 399257041Shselasky DPRINTFN(0, "CSR0 DATAEND\n"); 400184610Salfred goto not_complete; 401184610Salfred } 402257041Shselasky 403184610Salfred if (csr & MUSB2_MASK_CSR0L_SENTSTALL) { 404184610Salfred /* clear SENTSTALL */ 405184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 0); 406184610Salfred /* get latest status */ 407184610Salfred csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL); 408184610Salfred /* update EP0 state */ 409184610Salfred sc->sc_ep0_busy = 0; 410184610Salfred } 411184610Salfred if (csr & MUSB2_MASK_CSR0L_SETUPEND) { 412184610Salfred /* clear SETUPEND */ 413184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 414184610Salfred MUSB2_MASK_CSR0L_SETUPEND_CLR); 415184610Salfred /* get latest status */ 416184610Salfred csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL); 417184610Salfred /* update EP0 state */ 418184610Salfred sc->sc_ep0_busy = 0; 419184610Salfred } 420184610Salfred if (sc->sc_ep0_busy) { 421257041Shselasky DPRINTFN(0, "EP0 BUSY\n"); 422184610Salfred goto not_complete; 423184610Salfred } 424184610Salfred if (!(csr & MUSB2_MASK_CSR0L_RXPKTRDY)) { 425184610Salfred goto not_complete; 426184610Salfred } 427190721Sthompsa /* clear did stall flag */ 428190721Sthompsa td->did_stall = 0; 429184610Salfred /* get the packet byte count */ 430184610Salfred count = MUSB2_READ_2(sc, MUSB2_REG_RXCOUNT); 431184610Salfred 432184610Salfred /* verify data length */ 433184610Salfred if (count != td->remainder) { 434184610Salfred DPRINTFN(0, "Invalid SETUP packet " 435184610Salfred "length, %d bytes\n", count); 436190722Sthompsa MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 437190722Sthompsa MUSB2_MASK_CSR0L_RXPKTRDY_CLR); 438184610Salfred goto not_complete; 439184610Salfred } 440184610Salfred if (count != sizeof(req)) { 441184610Salfred DPRINTFN(0, "Unsupported SETUP packet " 442184610Salfred "length, %d bytes\n", count); 443190722Sthompsa MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 444190722Sthompsa MUSB2_MASK_CSR0L_RXPKTRDY_CLR); 445184610Salfred goto not_complete; 446184610Salfred } 447184610Salfred /* receive data */ 448184610Salfred bus_space_read_multi_1(sc->sc_io_tag, sc->sc_io_hdl, 449184610Salfred MUSB2_REG_EPFIFO(0), (void *)&req, sizeof(req)); 450184610Salfred 451184610Salfred /* copy data into real buffer */ 452194228Sthompsa usbd_copy_in(td->pc, 0, &req, sizeof(req)); 453184610Salfred 454184610Salfred td->offset = sizeof(req); 455184610Salfred td->remainder = 0; 456184610Salfred 457184610Salfred /* set pending command */ 458184610Salfred sc->sc_ep0_cmd = MUSB2_MASK_CSR0L_RXPKTRDY_CLR; 459184610Salfred 460184610Salfred /* we need set stall or dataend after this */ 461184610Salfred sc->sc_ep0_busy = 1; 462184610Salfred 463184610Salfred /* sneak peek the set address */ 464184610Salfred if ((req.bmRequestType == UT_WRITE_DEVICE) && 465184610Salfred (req.bRequest == UR_SET_ADDRESS)) { 466184610Salfred sc->sc_dv_addr = req.wValue[0] & 0x7F; 467184610Salfred } else { 468184610Salfred sc->sc_dv_addr = 0xFF; 469184610Salfred } 470257041Shselasky 471257041Shselasky musbotg_channel_free(sc, td); 472184610Salfred return (0); /* complete */ 473184610Salfred 474184610Salfrednot_complete: 475190721Sthompsa /* abort any ongoing transfer */ 476190721Sthompsa if (!td->did_stall) { 477190721Sthompsa DPRINTFN(4, "stalling\n"); 478190721Sthompsa MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 479190721Sthompsa MUSB2_MASK_CSR0L_SENDSTALL); 480190721Sthompsa td->did_stall = 1; 481190721Sthompsa } 482184610Salfred return (1); /* not complete */ 483184610Salfred} 484184610Salfred 485257041Shselaskystatic uint8_t 486257041Shselaskymusbotg_host_ctrl_setup_tx(struct musbotg_td *td) 487257041Shselasky{ 488257041Shselasky struct musbotg_softc *sc; 489257041Shselasky struct usb_device_request req; 490257041Shselasky uint8_t csr, csrh; 491257041Shselasky 492257041Shselasky /* get pointer to softc */ 493257041Shselasky sc = MUSBOTG_PC2SC(td->pc); 494257041Shselasky 495257041Shselasky if (td->channel == -1) 496257041Shselasky td->channel = musbotg_channel_alloc(sc, td); 497257041Shselasky 498257041Shselasky /* EP0 is busy, wait */ 499257041Shselasky if (td->channel == -1) 500257041Shselasky return (1); 501257041Shselasky 502257041Shselasky DPRINTFN(1, "ep_no=%d\n", td->channel); 503257041Shselasky 504257041Shselasky /* select endpoint 0 */ 505257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_EPINDEX, 0); 506257041Shselasky 507257041Shselasky /* read out FIFO status */ 508257041Shselasky csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL); 509257041Shselasky DPRINTFN(4, "csr=0x%02x\n", csr); 510257041Shselasky 511257041Shselasky /* Not ready yet yet */ 512257041Shselasky if (csr & MUSB2_MASK_CSR0L_TXPKTRDY) 513257041Shselasky return (1); 514257041Shselasky 515257041Shselasky /* Failed */ 516257041Shselasky if (csr & (MUSB2_MASK_CSR0L_RXSTALL | 517257041Shselasky MUSB2_MASK_CSR0L_ERROR)) 518257041Shselasky { 519257041Shselasky /* Clear status bit */ 520257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 0); 521257041Shselasky DPRINTFN(1, "error bit set, csr=0x%02x\n", csr); 522257041Shselasky td->error = 1; 523257041Shselasky } 524257041Shselasky 525257041Shselasky if (csr & MUSB2_MASK_CSR0L_NAKTIMO) { 526257041Shselasky DPRINTFN(1, "NAK timeout\n"); 527257041Shselasky 528257041Shselasky if (csr & MUSB2_MASK_CSR0L_TXFIFONEMPTY) { 529257041Shselasky csrh = MUSB2_READ_1(sc, MUSB2_REG_TXCSRH); 530257041Shselasky csrh |= MUSB2_MASK_CSR0H_FFLUSH; 531257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRH, csrh); 532257041Shselasky csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL); 533257041Shselasky if (csr & MUSB2_MASK_CSR0L_TXFIFONEMPTY) { 534257041Shselasky csrh = MUSB2_READ_1(sc, MUSB2_REG_TXCSRH); 535257041Shselasky csrh |= MUSB2_MASK_CSR0H_FFLUSH; 536257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRH, csrh); 537257041Shselasky csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL); 538257041Shselasky } 539257041Shselasky } 540257041Shselasky 541257041Shselasky csr &= ~MUSB2_MASK_CSR0L_NAKTIMO; 542257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, csr); 543257041Shselasky 544257041Shselasky td->error = 1; 545257041Shselasky } 546257041Shselasky 547257041Shselasky if (td->error) { 548257041Shselasky musbotg_channel_free(sc, td); 549257041Shselasky return (0); 550257041Shselasky } 551257041Shselasky 552257041Shselasky /* Fifo is not empty and there is no NAK timeout */ 553257041Shselasky if (csr & MUSB2_MASK_CSR0L_TXPKTRDY) 554257041Shselasky return (1); 555257041Shselasky 556257041Shselasky /* check if we are complete */ 557257041Shselasky if (td->remainder == 0) { 558257041Shselasky /* we are complete */ 559257041Shselasky musbotg_channel_free(sc, td); 560257041Shselasky return (0); 561257041Shselasky } 562257041Shselasky 563257041Shselasky /* copy data into real buffer */ 564257041Shselasky usbd_copy_out(td->pc, 0, &req, sizeof(req)); 565257041Shselasky 566257041Shselasky /* send data */ 567257041Shselasky bus_space_write_multi_1(sc->sc_io_tag, sc->sc_io_hdl, 568257041Shselasky MUSB2_REG_EPFIFO(0), (void *)&req, sizeof(req)); 569257041Shselasky 570257041Shselasky /* update offset and remainder */ 571257041Shselasky td->offset += sizeof(req); 572257041Shselasky td->remainder -= sizeof(req); 573257041Shselasky 574257041Shselasky 575257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_TXNAKLIMIT, MAX_NAK_TO); 576257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_TXFADDR(0), td->dev_addr); 577257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_TXHADDR(0), td->haddr); 578257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_TXHUBPORT(0), td->hport); 579257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_TXTI, td->transfer_type); 580257041Shselasky 581257041Shselasky /* write command */ 582257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 583257041Shselasky MUSB2_MASK_CSR0L_TXPKTRDY | 584257041Shselasky MUSB2_MASK_CSR0L_SETUPPKT); 585257041Shselasky 586257041Shselasky /* Just to be consistent, not used above */ 587257041Shselasky td->transaction_started = 1; 588257041Shselasky 589257041Shselasky return (1); /* in progress */ 590257041Shselasky} 591257041Shselasky 592184610Salfred/* Control endpoint only data handling functions (RX/TX/SYNC) */ 593184610Salfred 594184610Salfredstatic uint8_t 595257041Shselaskymusbotg_dev_ctrl_data_rx(struct musbotg_td *td) 596184610Salfred{ 597192984Sthompsa struct usb_page_search buf_res; 598184610Salfred struct musbotg_softc *sc; 599184610Salfred uint16_t count; 600184610Salfred uint8_t csr; 601184610Salfred uint8_t got_short; 602184610Salfred 603184610Salfred /* get pointer to softc */ 604184610Salfred sc = MUSBOTG_PC2SC(td->pc); 605184610Salfred 606184610Salfred /* select endpoint 0 */ 607184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_EPINDEX, 0); 608184610Salfred 609184610Salfred /* check if a command is pending */ 610184610Salfred if (sc->sc_ep0_cmd) { 611184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, sc->sc_ep0_cmd); 612184610Salfred sc->sc_ep0_cmd = 0; 613184610Salfred } 614184610Salfred /* read out FIFO status */ 615184610Salfred csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL); 616184610Salfred 617184610Salfred DPRINTFN(4, "csr=0x%02x\n", csr); 618184610Salfred 619184610Salfred got_short = 0; 620184610Salfred 621184610Salfred if (csr & (MUSB2_MASK_CSR0L_SETUPEND | 622184610Salfred MUSB2_MASK_CSR0L_SENTSTALL)) { 623184610Salfred if (td->remainder == 0) { 624184610Salfred /* 625184610Salfred * We are actually complete and have 626184610Salfred * received the next SETUP 627184610Salfred */ 628184610Salfred DPRINTFN(4, "faking complete\n"); 629184610Salfred return (0); /* complete */ 630184610Salfred } 631184610Salfred /* 632184610Salfred * USB Host Aborted the transfer. 633184610Salfred */ 634184610Salfred td->error = 1; 635184610Salfred return (0); /* complete */ 636184610Salfred } 637184610Salfred if (!(csr & MUSB2_MASK_CSR0L_RXPKTRDY)) { 638184610Salfred return (1); /* not complete */ 639184610Salfred } 640184610Salfred /* get the packet byte count */ 641184610Salfred count = MUSB2_READ_2(sc, MUSB2_REG_RXCOUNT); 642184610Salfred 643184610Salfred /* verify the packet byte count */ 644184610Salfred if (count != td->max_frame_size) { 645184610Salfred if (count < td->max_frame_size) { 646184610Salfred /* we have a short packet */ 647184610Salfred td->short_pkt = 1; 648184610Salfred got_short = 1; 649184610Salfred } else { 650184610Salfred /* invalid USB packet */ 651184610Salfred td->error = 1; 652184610Salfred return (0); /* we are complete */ 653184610Salfred } 654184610Salfred } 655184610Salfred /* verify the packet byte count */ 656184610Salfred if (count > td->remainder) { 657184610Salfred /* invalid USB packet */ 658184610Salfred td->error = 1; 659184610Salfred return (0); /* we are complete */ 660184610Salfred } 661184610Salfred while (count > 0) { 662184610Salfred uint32_t temp; 663184610Salfred 664194228Sthompsa usbd_get_page(td->pc, td->offset, &buf_res); 665184610Salfred 666184610Salfred /* get correct length */ 667184610Salfred if (buf_res.length > count) { 668184610Salfred buf_res.length = count; 669184610Salfred } 670184610Salfred /* check for unaligned memory address */ 671184610Salfred if (USB_P2U(buf_res.buffer) & 3) { 672184610Salfred 673184610Salfred temp = count & ~3; 674184610Salfred 675184610Salfred if (temp) { 676184610Salfred /* receive data 4 bytes at a time */ 677184610Salfred bus_space_read_multi_4(sc->sc_io_tag, sc->sc_io_hdl, 678184610Salfred MUSB2_REG_EPFIFO(0), sc->sc_bounce_buf, 679184610Salfred temp / 4); 680184610Salfred } 681184610Salfred temp = count & 3; 682184610Salfred if (temp) { 683184610Salfred /* receive data 1 byte at a time */ 684184610Salfred bus_space_read_multi_1(sc->sc_io_tag, sc->sc_io_hdl, 685184610Salfred MUSB2_REG_EPFIFO(0), 686184610Salfred (void *)(&sc->sc_bounce_buf[count / 4]), temp); 687184610Salfred } 688194228Sthompsa usbd_copy_in(td->pc, td->offset, 689184610Salfred sc->sc_bounce_buf, count); 690184610Salfred 691184610Salfred /* update offset and remainder */ 692184610Salfred td->offset += count; 693184610Salfred td->remainder -= count; 694184610Salfred break; 695184610Salfred } 696184610Salfred /* check if we can optimise */ 697184610Salfred if (buf_res.length >= 4) { 698184610Salfred 699184610Salfred /* receive data 4 bytes at a time */ 700184610Salfred bus_space_read_multi_4(sc->sc_io_tag, sc->sc_io_hdl, 701184610Salfred MUSB2_REG_EPFIFO(0), buf_res.buffer, 702184610Salfred buf_res.length / 4); 703184610Salfred 704184610Salfred temp = buf_res.length & ~3; 705184610Salfred 706184610Salfred /* update counters */ 707184610Salfred count -= temp; 708184610Salfred td->offset += temp; 709184610Salfred td->remainder -= temp; 710184610Salfred continue; 711184610Salfred } 712184610Salfred /* receive data */ 713184610Salfred bus_space_read_multi_1(sc->sc_io_tag, sc->sc_io_hdl, 714184610Salfred MUSB2_REG_EPFIFO(0), buf_res.buffer, buf_res.length); 715184610Salfred 716184610Salfred /* update counters */ 717184610Salfred count -= buf_res.length; 718184610Salfred td->offset += buf_res.length; 719184610Salfred td->remainder -= buf_res.length; 720184610Salfred } 721184610Salfred 722184610Salfred /* check if we are complete */ 723184610Salfred if ((td->remainder == 0) || got_short) { 724184610Salfred if (td->short_pkt) { 725184610Salfred /* we are complete */ 726184610Salfred sc->sc_ep0_cmd = MUSB2_MASK_CSR0L_RXPKTRDY_CLR; 727184610Salfred return (0); 728184610Salfred } 729184610Salfred /* else need to receive a zero length packet */ 730184610Salfred } 731184610Salfred /* write command - need more data */ 732184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 733184610Salfred MUSB2_MASK_CSR0L_RXPKTRDY_CLR); 734184610Salfred return (1); /* not complete */ 735184610Salfred} 736184610Salfred 737184610Salfredstatic uint8_t 738257041Shselaskymusbotg_dev_ctrl_data_tx(struct musbotg_td *td) 739184610Salfred{ 740192984Sthompsa struct usb_page_search buf_res; 741184610Salfred struct musbotg_softc *sc; 742184610Salfred uint16_t count; 743184610Salfred uint8_t csr; 744184610Salfred 745184610Salfred /* get pointer to softc */ 746184610Salfred sc = MUSBOTG_PC2SC(td->pc); 747184610Salfred 748184610Salfred /* select endpoint 0 */ 749184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_EPINDEX, 0); 750184610Salfred 751184610Salfred /* check if a command is pending */ 752184610Salfred if (sc->sc_ep0_cmd) { 753184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, sc->sc_ep0_cmd); 754184610Salfred sc->sc_ep0_cmd = 0; 755184610Salfred } 756184610Salfred /* read out FIFO status */ 757184610Salfred csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL); 758184610Salfred 759184610Salfred DPRINTFN(4, "csr=0x%02x\n", csr); 760184610Salfred 761184610Salfred if (csr & (MUSB2_MASK_CSR0L_SETUPEND | 762184610Salfred MUSB2_MASK_CSR0L_SENTSTALL)) { 763184610Salfred /* 764184610Salfred * The current transfer was aborted 765184610Salfred * by the USB Host 766184610Salfred */ 767184610Salfred td->error = 1; 768184610Salfred return (0); /* complete */ 769184610Salfred } 770184610Salfred if (csr & MUSB2_MASK_CSR0L_TXPKTRDY) { 771184610Salfred return (1); /* not complete */ 772184610Salfred } 773184610Salfred count = td->max_frame_size; 774184610Salfred if (td->remainder < count) { 775184610Salfred /* we have a short packet */ 776184610Salfred td->short_pkt = 1; 777184610Salfred count = td->remainder; 778184610Salfred } 779184610Salfred while (count > 0) { 780184610Salfred uint32_t temp; 781184610Salfred 782194228Sthompsa usbd_get_page(td->pc, td->offset, &buf_res); 783184610Salfred 784184610Salfred /* get correct length */ 785184610Salfred if (buf_res.length > count) { 786184610Salfred buf_res.length = count; 787184610Salfred } 788184610Salfred /* check for unaligned memory address */ 789184610Salfred if (USB_P2U(buf_res.buffer) & 3) { 790184610Salfred 791194228Sthompsa usbd_copy_out(td->pc, td->offset, 792184610Salfred sc->sc_bounce_buf, count); 793184610Salfred 794184610Salfred temp = count & ~3; 795184610Salfred 796184610Salfred if (temp) { 797184610Salfred /* transmit data 4 bytes at a time */ 798184610Salfred bus_space_write_multi_4(sc->sc_io_tag, sc->sc_io_hdl, 799184610Salfred MUSB2_REG_EPFIFO(0), sc->sc_bounce_buf, 800184610Salfred temp / 4); 801184610Salfred } 802184610Salfred temp = count & 3; 803184610Salfred if (temp) { 804184610Salfred /* receive data 1 byte at a time */ 805184610Salfred bus_space_write_multi_1(sc->sc_io_tag, sc->sc_io_hdl, 806184610Salfred MUSB2_REG_EPFIFO(0), 807184610Salfred ((void *)&sc->sc_bounce_buf[count / 4]), temp); 808184610Salfred } 809184610Salfred /* update offset and remainder */ 810184610Salfred td->offset += count; 811184610Salfred td->remainder -= count; 812184610Salfred break; 813184610Salfred } 814184610Salfred /* check if we can optimise */ 815184610Salfred if (buf_res.length >= 4) { 816184610Salfred 817184610Salfred /* transmit data 4 bytes at a time */ 818184610Salfred bus_space_write_multi_4(sc->sc_io_tag, sc->sc_io_hdl, 819184610Salfred MUSB2_REG_EPFIFO(0), buf_res.buffer, 820184610Salfred buf_res.length / 4); 821184610Salfred 822184610Salfred temp = buf_res.length & ~3; 823184610Salfred 824184610Salfred /* update counters */ 825184610Salfred count -= temp; 826184610Salfred td->offset += temp; 827184610Salfred td->remainder -= temp; 828184610Salfred continue; 829184610Salfred } 830184610Salfred /* transmit data */ 831184610Salfred bus_space_write_multi_1(sc->sc_io_tag, sc->sc_io_hdl, 832184610Salfred MUSB2_REG_EPFIFO(0), buf_res.buffer, buf_res.length); 833184610Salfred 834184610Salfred /* update counters */ 835184610Salfred count -= buf_res.length; 836184610Salfred td->offset += buf_res.length; 837184610Salfred td->remainder -= buf_res.length; 838184610Salfred } 839184610Salfred 840184610Salfred /* check remainder */ 841184610Salfred if (td->remainder == 0) { 842184610Salfred if (td->short_pkt) { 843184610Salfred sc->sc_ep0_cmd = MUSB2_MASK_CSR0L_TXPKTRDY; 844184610Salfred return (0); /* complete */ 845184610Salfred } 846184610Salfred /* else we need to transmit a short packet */ 847184610Salfred } 848184610Salfred /* write command */ 849184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 850184610Salfred MUSB2_MASK_CSR0L_TXPKTRDY); 851184610Salfred 852184610Salfred return (1); /* not complete */ 853184610Salfred} 854184610Salfred 855184610Salfredstatic uint8_t 856257041Shselaskymusbotg_host_ctrl_data_rx(struct musbotg_td *td) 857184610Salfred{ 858257041Shselasky struct usb_page_search buf_res; 859184610Salfred struct musbotg_softc *sc; 860257041Shselasky uint16_t count; 861184610Salfred uint8_t csr; 862257041Shselasky uint8_t got_short; 863184610Salfred 864184610Salfred /* get pointer to softc */ 865184610Salfred sc = MUSBOTG_PC2SC(td->pc); 866184610Salfred 867257041Shselasky if (td->channel == -1) 868257041Shselasky td->channel = musbotg_channel_alloc(sc, td); 869257041Shselasky 870257041Shselasky /* EP0 is busy, wait */ 871257041Shselasky if (td->channel == -1) 872257041Shselasky return (1); 873257041Shselasky 874257041Shselasky DPRINTFN(1, "ep_no=%d\n", td->channel); 875257041Shselasky 876184610Salfred /* select endpoint 0 */ 877184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_EPINDEX, 0); 878184610Salfred 879257041Shselasky /* read out FIFO status */ 880257041Shselasky csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL); 881257041Shselasky 882257041Shselasky DPRINTFN(4, "csr=0x%02x\n", csr); 883257041Shselasky 884257041Shselasky got_short = 0; 885257041Shselasky if (!td->transaction_started) { 886257041Shselasky td->transaction_started = 1; 887257041Shselasky 888257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_RXNAKLIMIT, MAX_NAK_TO); 889257041Shselasky 890257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_RXFADDR(0), 891257041Shselasky td->dev_addr); 892257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_RXHADDR(0), td->haddr); 893257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_RXHUBPORT(0), td->hport); 894257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_RXTI, td->transfer_type); 895257041Shselasky 896257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 897257041Shselasky MUSB2_MASK_CSR0L_REQPKT); 898257041Shselasky 899257041Shselasky return (1); 900257041Shselasky } 901257041Shselasky 902257041Shselasky if (csr & MUSB2_MASK_CSR0L_NAKTIMO) { 903257041Shselasky csr &= ~MUSB2_MASK_CSR0L_REQPKT; 904257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, csr); 905257041Shselasky 906257041Shselasky csr &= ~MUSB2_MASK_CSR0L_NAKTIMO; 907257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, csr); 908257041Shselasky 909257041Shselasky td->error = 1; 910257041Shselasky } 911257041Shselasky 912257041Shselasky /* Failed */ 913257041Shselasky if (csr & (MUSB2_MASK_CSR0L_RXSTALL | 914257041Shselasky MUSB2_MASK_CSR0L_ERROR)) 915257041Shselasky { 916257041Shselasky /* Clear status bit */ 917257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 0); 918257041Shselasky DPRINTFN(1, "error bit set, csr=0x%02x\n", csr); 919257041Shselasky td->error = 1; 920257041Shselasky } 921257041Shselasky 922257041Shselasky if (td->error) { 923257041Shselasky musbotg_channel_free(sc, td); 924257041Shselasky return (0); /* we are complete */ 925257041Shselasky } 926257041Shselasky 927257041Shselasky if (!(csr & MUSB2_MASK_CSR0L_RXPKTRDY)) 928257041Shselasky return (1); /* not yet */ 929257041Shselasky 930257041Shselasky /* get the packet byte count */ 931257041Shselasky count = MUSB2_READ_2(sc, MUSB2_REG_RXCOUNT); 932257041Shselasky 933257041Shselasky /* verify the packet byte count */ 934257041Shselasky if (count != td->max_frame_size) { 935257041Shselasky if (count < td->max_frame_size) { 936257041Shselasky /* we have a short packet */ 937257041Shselasky td->short_pkt = 1; 938257041Shselasky got_short = 1; 939257041Shselasky } else { 940257041Shselasky /* invalid USB packet */ 941257041Shselasky td->error = 1; 942257041Shselasky musbotg_channel_free(sc, td); 943257041Shselasky return (0); /* we are complete */ 944257041Shselasky } 945257041Shselasky } 946257041Shselasky /* verify the packet byte count */ 947257041Shselasky if (count > td->remainder) { 948257041Shselasky /* invalid USB packet */ 949257041Shselasky td->error = 1; 950257041Shselasky musbotg_channel_free(sc, td); 951257041Shselasky return (0); /* we are complete */ 952257041Shselasky } 953257041Shselasky while (count > 0) { 954257041Shselasky uint32_t temp; 955257041Shselasky 956257041Shselasky usbd_get_page(td->pc, td->offset, &buf_res); 957257041Shselasky 958257041Shselasky /* get correct length */ 959257041Shselasky if (buf_res.length > count) { 960257041Shselasky buf_res.length = count; 961257041Shselasky } 962257041Shselasky /* check for unaligned memory address */ 963257041Shselasky if (USB_P2U(buf_res.buffer) & 3) { 964257041Shselasky 965257041Shselasky temp = count & ~3; 966257041Shselasky 967257041Shselasky if (temp) { 968257041Shselasky /* receive data 4 bytes at a time */ 969257041Shselasky bus_space_read_multi_4(sc->sc_io_tag, sc->sc_io_hdl, 970257041Shselasky MUSB2_REG_EPFIFO(0), sc->sc_bounce_buf, 971257041Shselasky temp / 4); 972257041Shselasky } 973257041Shselasky temp = count & 3; 974257041Shselasky if (temp) { 975257041Shselasky /* receive data 1 byte at a time */ 976257041Shselasky bus_space_read_multi_1(sc->sc_io_tag, sc->sc_io_hdl, 977257041Shselasky MUSB2_REG_EPFIFO(0), 978257041Shselasky (void *)(&sc->sc_bounce_buf[count / 4]), temp); 979257041Shselasky } 980257041Shselasky usbd_copy_in(td->pc, td->offset, 981257041Shselasky sc->sc_bounce_buf, count); 982257041Shselasky 983257041Shselasky /* update offset and remainder */ 984257041Shselasky td->offset += count; 985257041Shselasky td->remainder -= count; 986257041Shselasky break; 987257041Shselasky } 988257041Shselasky /* check if we can optimise */ 989257041Shselasky if (buf_res.length >= 4) { 990257041Shselasky 991257041Shselasky /* receive data 4 bytes at a time */ 992257041Shselasky bus_space_read_multi_4(sc->sc_io_tag, sc->sc_io_hdl, 993257041Shselasky MUSB2_REG_EPFIFO(0), buf_res.buffer, 994257041Shselasky buf_res.length / 4); 995257041Shselasky 996257041Shselasky temp = buf_res.length & ~3; 997257041Shselasky 998257041Shselasky /* update counters */ 999257041Shselasky count -= temp; 1000257041Shselasky td->offset += temp; 1001257041Shselasky td->remainder -= temp; 1002257041Shselasky continue; 1003257041Shselasky } 1004257041Shselasky /* receive data */ 1005257041Shselasky bus_space_read_multi_1(sc->sc_io_tag, sc->sc_io_hdl, 1006257041Shselasky MUSB2_REG_EPFIFO(0), buf_res.buffer, buf_res.length); 1007257041Shselasky 1008257041Shselasky /* update counters */ 1009257041Shselasky count -= buf_res.length; 1010257041Shselasky td->offset += buf_res.length; 1011257041Shselasky td->remainder -= buf_res.length; 1012257041Shselasky } 1013257041Shselasky 1014257041Shselasky csr &= ~MUSB2_MASK_CSR0L_RXPKTRDY; 1015257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, csr); 1016257041Shselasky 1017257041Shselasky /* check if we are complete */ 1018257041Shselasky if ((td->remainder == 0) || got_short) { 1019257041Shselasky if (td->short_pkt) { 1020257041Shselasky /* we are complete */ 1021257041Shselasky 1022257041Shselasky musbotg_channel_free(sc, td); 1023257041Shselasky return (0); 1024257041Shselasky } 1025257041Shselasky /* else need to receive a zero length packet */ 1026257041Shselasky } 1027257041Shselasky 1028257041Shselasky td->transaction_started = 1; 1029257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 1030257041Shselasky MUSB2_MASK_CSR0L_REQPKT); 1031257041Shselasky 1032257041Shselasky return (1); /* not complete */ 1033257041Shselasky} 1034257041Shselasky 1035257041Shselaskystatic uint8_t 1036257041Shselaskymusbotg_host_ctrl_data_tx(struct musbotg_td *td) 1037257041Shselasky{ 1038257041Shselasky struct usb_page_search buf_res; 1039257041Shselasky struct musbotg_softc *sc; 1040257041Shselasky uint16_t count; 1041257041Shselasky uint8_t csr, csrh; 1042257041Shselasky 1043257041Shselasky /* get pointer to softc */ 1044257041Shselasky sc = MUSBOTG_PC2SC(td->pc); 1045257041Shselasky 1046257041Shselasky if (td->channel == -1) 1047257041Shselasky td->channel = musbotg_channel_alloc(sc, td); 1048257041Shselasky 1049257041Shselasky /* No free EPs */ 1050257041Shselasky if (td->channel == -1) 1051257041Shselasky return (1); 1052257041Shselasky 1053257041Shselasky DPRINTFN(1, "ep_no=%d\n", td->channel); 1054257041Shselasky 1055257041Shselasky /* select endpoint */ 1056257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_EPINDEX, 0); 1057257041Shselasky 1058257041Shselasky /* read out FIFO status */ 1059257041Shselasky csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL); 1060257041Shselasky DPRINTFN(4, "csr=0x%02x\n", csr); 1061257041Shselasky 1062257041Shselasky if (csr & (MUSB2_MASK_CSR0L_RXSTALL | 1063257041Shselasky MUSB2_MASK_CSR0L_ERROR)) { 1064257041Shselasky /* clear status bits */ 1065257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 0); 1066257041Shselasky td->error = 1; 1067257041Shselasky } 1068257041Shselasky 1069257041Shselasky if (csr & MUSB2_MASK_CSR0L_NAKTIMO ) { 1070257041Shselasky 1071257041Shselasky if (csr & MUSB2_MASK_CSR0L_TXFIFONEMPTY) { 1072257041Shselasky csrh = MUSB2_READ_1(sc, MUSB2_REG_TXCSRH); 1073257041Shselasky csrh |= MUSB2_MASK_CSR0H_FFLUSH; 1074257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRH, csrh); 1075257041Shselasky csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL); 1076257041Shselasky if (csr & MUSB2_MASK_CSR0L_TXFIFONEMPTY) { 1077257041Shselasky csrh = MUSB2_READ_1(sc, MUSB2_REG_TXCSRH); 1078257041Shselasky csrh |= MUSB2_MASK_CSR0H_FFLUSH; 1079257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRH, csrh); 1080257041Shselasky csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL); 1081257041Shselasky } 1082257041Shselasky } 1083257041Shselasky 1084257041Shselasky csr &= ~MUSB2_MASK_CSR0L_NAKTIMO; 1085257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, csr); 1086257041Shselasky 1087257041Shselasky td->error = 1; 1088257041Shselasky } 1089257041Shselasky 1090257041Shselasky 1091257041Shselasky if (td->error) { 1092257041Shselasky musbotg_channel_free(sc, td); 1093257041Shselasky return (0); /* complete */ 1094257041Shselasky } 1095257041Shselasky 1096257041Shselasky /* 1097257041Shselasky * Wait while FIFO is empty. 1098257041Shselasky * Do not flush it because it will cause transactions 1099257041Shselasky * with size more then packet size. It might upset 1100257041Shselasky * some devices 1101257041Shselasky */ 1102257041Shselasky if (csr & MUSB2_MASK_CSR0L_TXFIFONEMPTY) 1103257041Shselasky return (1); 1104257041Shselasky 1105257041Shselasky /* Packet still being processed */ 1106257041Shselasky if (csr & MUSB2_MASK_CSR0L_TXPKTRDY) 1107257041Shselasky return (1); 1108257041Shselasky 1109257041Shselasky if (td->transaction_started) { 1110257041Shselasky /* check remainder */ 1111257041Shselasky if (td->remainder == 0) { 1112257041Shselasky if (td->short_pkt) { 1113257041Shselasky musbotg_channel_free(sc, td); 1114257041Shselasky return (0); /* complete */ 1115257041Shselasky } 1116257041Shselasky /* else we need to transmit a short packet */ 1117257041Shselasky } 1118257041Shselasky 1119257041Shselasky /* We're not complete - more transactions required */ 1120257041Shselasky td->transaction_started = 0; 1121257041Shselasky } 1122257041Shselasky 1123257041Shselasky /* check for short packet */ 1124257041Shselasky count = td->max_frame_size; 1125257041Shselasky if (td->remainder < count) { 1126257041Shselasky /* we have a short packet */ 1127257041Shselasky td->short_pkt = 1; 1128257041Shselasky count = td->remainder; 1129257041Shselasky } 1130257041Shselasky 1131257041Shselasky while (count > 0) { 1132257041Shselasky uint32_t temp; 1133257041Shselasky 1134257041Shselasky usbd_get_page(td->pc, td->offset, &buf_res); 1135257041Shselasky 1136257041Shselasky /* get correct length */ 1137257041Shselasky if (buf_res.length > count) { 1138257041Shselasky buf_res.length = count; 1139257041Shselasky } 1140257041Shselasky /* check for unaligned memory address */ 1141257041Shselasky if (USB_P2U(buf_res.buffer) & 3) { 1142257041Shselasky 1143257041Shselasky usbd_copy_out(td->pc, td->offset, 1144257041Shselasky sc->sc_bounce_buf, count); 1145257041Shselasky 1146257041Shselasky temp = count & ~3; 1147257041Shselasky 1148257041Shselasky if (temp) { 1149257041Shselasky /* transmit data 4 bytes at a time */ 1150257041Shselasky bus_space_write_multi_4(sc->sc_io_tag, 1151257041Shselasky sc->sc_io_hdl, MUSB2_REG_EPFIFO(0), 1152257041Shselasky sc->sc_bounce_buf, temp / 4); 1153257041Shselasky } 1154257041Shselasky temp = count & 3; 1155257041Shselasky if (temp) { 1156257041Shselasky /* receive data 1 byte at a time */ 1157257041Shselasky bus_space_write_multi_1(sc->sc_io_tag, sc->sc_io_hdl, 1158257041Shselasky MUSB2_REG_EPFIFO(0), 1159257041Shselasky ((void *)&sc->sc_bounce_buf[count / 4]), temp); 1160257041Shselasky } 1161257041Shselasky /* update offset and remainder */ 1162257041Shselasky td->offset += count; 1163257041Shselasky td->remainder -= count; 1164257041Shselasky break; 1165257041Shselasky } 1166257041Shselasky /* check if we can optimise */ 1167257041Shselasky if (buf_res.length >= 4) { 1168257041Shselasky 1169257041Shselasky /* transmit data 4 bytes at a time */ 1170257041Shselasky bus_space_write_multi_4(sc->sc_io_tag, sc->sc_io_hdl, 1171257041Shselasky MUSB2_REG_EPFIFO(0), buf_res.buffer, 1172257041Shselasky buf_res.length / 4); 1173257041Shselasky 1174257041Shselasky temp = buf_res.length & ~3; 1175257041Shselasky 1176257041Shselasky /* update counters */ 1177257041Shselasky count -= temp; 1178257041Shselasky td->offset += temp; 1179257041Shselasky td->remainder -= temp; 1180257041Shselasky continue; 1181257041Shselasky } 1182257041Shselasky /* transmit data */ 1183257041Shselasky bus_space_write_multi_1(sc->sc_io_tag, sc->sc_io_hdl, 1184257041Shselasky MUSB2_REG_EPFIFO(0), buf_res.buffer, 1185257041Shselasky buf_res.length); 1186257041Shselasky 1187257041Shselasky /* update counters */ 1188257041Shselasky count -= buf_res.length; 1189257041Shselasky td->offset += buf_res.length; 1190257041Shselasky td->remainder -= buf_res.length; 1191257041Shselasky } 1192257041Shselasky 1193257041Shselasky /* Function address */ 1194257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_TXFADDR(0), td->dev_addr); 1195257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_TXHADDR(0), td->haddr); 1196257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_TXHUBPORT(0), td->hport); 1197257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_TXTI, td->transfer_type); 1198257041Shselasky 1199257041Shselasky /* TX NAK timeout */ 1200257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_TXNAKLIMIT, MAX_NAK_TO); 1201257041Shselasky 1202257041Shselasky /* write command */ 1203257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 1204257041Shselasky MUSB2_MASK_CSR0L_TXPKTRDY); 1205257041Shselasky 1206257041Shselasky td->transaction_started = 1; 1207257041Shselasky 1208257041Shselasky return (1); /* not complete */ 1209257041Shselasky} 1210257041Shselasky 1211257041Shselaskystatic uint8_t 1212257041Shselaskymusbotg_dev_ctrl_status(struct musbotg_td *td) 1213257041Shselasky{ 1214257041Shselasky struct musbotg_softc *sc; 1215257041Shselasky uint8_t csr; 1216257041Shselasky 1217257041Shselasky /* get pointer to softc */ 1218257041Shselasky sc = MUSBOTG_PC2SC(td->pc); 1219257041Shselasky 1220257041Shselasky /* select endpoint 0 */ 1221257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_EPINDEX, 0); 1222257041Shselasky 1223184610Salfred if (sc->sc_ep0_busy) { 1224184610Salfred sc->sc_ep0_busy = 0; 1225184610Salfred sc->sc_ep0_cmd |= MUSB2_MASK_CSR0L_DATAEND; 1226184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, sc->sc_ep0_cmd); 1227184610Salfred sc->sc_ep0_cmd = 0; 1228184610Salfred } 1229184610Salfred /* read out FIFO status */ 1230184610Salfred csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL); 1231184610Salfred 1232184610Salfred DPRINTFN(4, "csr=0x%02x\n", csr); 1233184610Salfred 1234184610Salfred if (csr & MUSB2_MASK_CSR0L_DATAEND) { 1235184610Salfred /* wait for interrupt */ 1236184610Salfred return (1); /* not complete */ 1237184610Salfred } 1238184610Salfred if (sc->sc_dv_addr != 0xFF) { 1239184610Salfred /* write function address */ 1240184610Salfred musbotg_set_address(sc, sc->sc_dv_addr); 1241184610Salfred } 1242257041Shselasky 1243257041Shselasky musbotg_channel_free(sc, td); 1244184610Salfred return (0); /* complete */ 1245184610Salfred} 1246184610Salfred 1247184610Salfredstatic uint8_t 1248257041Shselaskymusbotg_host_ctrl_status_rx(struct musbotg_td *td) 1249184610Salfred{ 1250257041Shselasky struct musbotg_softc *sc; 1251257041Shselasky uint8_t csr, csrh; 1252257041Shselasky 1253257041Shselasky /* get pointer to softc */ 1254257041Shselasky sc = MUSBOTG_PC2SC(td->pc); 1255257041Shselasky 1256257041Shselasky if (td->channel == -1) 1257257041Shselasky td->channel = musbotg_channel_alloc(sc, td); 1258257041Shselasky 1259257041Shselasky /* EP0 is busy, wait */ 1260257041Shselasky if (td->channel == -1) 1261257041Shselasky return (1); 1262257041Shselasky 1263257041Shselasky DPRINTFN(1, "ep_no=%d\n", td->channel); 1264257041Shselasky 1265257041Shselasky /* select endpoint 0 */ 1266257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_EPINDEX, 0); 1267257041Shselasky 1268257041Shselasky if (!td->transaction_started) { 1269257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_RXFADDR(0), 1270257041Shselasky td->dev_addr); 1271257041Shselasky 1272257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_RXHADDR(0), td->haddr); 1273257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_RXHUBPORT(0), td->hport); 1274257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_RXTI, td->transfer_type); 1275257041Shselasky 1276257041Shselasky /* RX NAK timeout */ 1277257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_RXNAKLIMIT, MAX_NAK_TO); 1278257041Shselasky 1279257041Shselasky td->transaction_started = 1; 1280257041Shselasky 1281257041Shselasky /* Disable PING */ 1282257041Shselasky csrh = MUSB2_READ_1(sc, MUSB2_REG_RXCSRH); 1283257041Shselasky csrh |= MUSB2_MASK_CSR0H_PING_DIS; 1284257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_RXCSRH, csrh); 1285257041Shselasky 1286257041Shselasky /* write command */ 1287257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 1288257041Shselasky MUSB2_MASK_CSR0L_STATUSPKT | 1289257041Shselasky MUSB2_MASK_CSR0L_REQPKT); 1290257041Shselasky 1291257041Shselasky return (1); /* Just started */ 1292257041Shselasky 1293257041Shselasky } 1294257041Shselasky 1295257041Shselasky csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL); 1296257041Shselasky 1297257041Shselasky DPRINTFN(4, "IN STATUS csr=0x%02x\n", csr); 1298257041Shselasky 1299257041Shselasky if (csr & MUSB2_MASK_CSR0L_RXPKTRDY) { 1300257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 1301257041Shselasky MUSB2_MASK_CSR0L_RXPKTRDY_CLR); 1302257041Shselasky musbotg_channel_free(sc, td); 1303257041Shselasky return (0); /* complete */ 1304257041Shselasky } 1305257041Shselasky 1306257041Shselasky if (csr & MUSB2_MASK_CSR0L_NAKTIMO) { 1307257041Shselasky csr &= ~ (MUSB2_MASK_CSR0L_STATUSPKT | 1308257041Shselasky MUSB2_MASK_CSR0L_REQPKT); 1309257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, csr); 1310257041Shselasky 1311257041Shselasky csr &= ~MUSB2_MASK_CSR0L_NAKTIMO; 1312257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, csr); 1313257041Shselasky td->error = 1; 1314257041Shselasky } 1315257041Shselasky 1316257041Shselasky /* Failed */ 1317257041Shselasky if (csr & (MUSB2_MASK_CSR0L_RXSTALL | 1318257041Shselasky MUSB2_MASK_CSR0L_ERROR)) 1319257041Shselasky { 1320257041Shselasky /* Clear status bit */ 1321257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 0); 1322257041Shselasky DPRINTFN(1, "error bit set, csr=0x%02x\n", csr); 1323257041Shselasky td->error = 1; 1324257041Shselasky } 1325257041Shselasky 1326257041Shselasky if (td->error) { 1327257041Shselasky musbotg_channel_free(sc, td); 1328257041Shselasky return (0); 1329257041Shselasky } 1330257041Shselasky 1331257041Shselasky return (1); /* Not ready yet */ 1332257041Shselasky} 1333257041Shselasky 1334257041Shselaskystatic uint8_t 1335257041Shselaskymusbotg_host_ctrl_status_tx(struct musbotg_td *td) 1336257041Shselasky{ 1337257041Shselasky struct musbotg_softc *sc; 1338257041Shselasky uint8_t csr; 1339257041Shselasky 1340257041Shselasky /* get pointer to softc */ 1341257041Shselasky sc = MUSBOTG_PC2SC(td->pc); 1342257041Shselasky 1343257041Shselasky if (td->channel == -1) 1344257041Shselasky td->channel = musbotg_channel_alloc(sc, td); 1345257041Shselasky 1346257041Shselasky /* EP0 is busy, wait */ 1347257041Shselasky if (td->channel == -1) 1348257041Shselasky return (1); 1349257041Shselasky 1350257041Shselasky DPRINTFN(1, "ep_no=%d/%d [%d@%d.%d/%02x]\n", td->channel, td->transaction_started, 1351257041Shselasky td->dev_addr,td->haddr,td->hport, td->transfer_type); 1352257041Shselasky 1353257041Shselasky /* select endpoint 0 */ 1354257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_EPINDEX, 0); 1355257041Shselasky 1356257041Shselasky csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL); 1357257041Shselasky DPRINTFN(4, "csr=0x%02x\n", csr); 1358257041Shselasky 1359257041Shselasky /* Not yet */ 1360257041Shselasky if (csr & MUSB2_MASK_CSR0L_TXPKTRDY) 1361257041Shselasky return (1); 1362257041Shselasky 1363257041Shselasky /* Failed */ 1364257041Shselasky if (csr & (MUSB2_MASK_CSR0L_RXSTALL | 1365257041Shselasky MUSB2_MASK_CSR0L_ERROR)) 1366257041Shselasky { 1367257041Shselasky /* Clear status bit */ 1368257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 0); 1369257041Shselasky DPRINTFN(1, "error bit set, csr=0x%02x\n", csr); 1370257041Shselasky td->error = 1; 1371257041Shselasky musbotg_channel_free(sc, td); 1372257041Shselasky return (0); /* complete */ 1373257041Shselasky } 1374257041Shselasky 1375257041Shselasky if (td->transaction_started) { 1376257041Shselasky musbotg_channel_free(sc, td); 1377257041Shselasky return (0); /* complete */ 1378257041Shselasky } 1379257041Shselasky 1380257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_RXCSRH, MUSB2_MASK_CSR0H_PING_DIS); 1381257041Shselasky 1382257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_TXFADDR(0), td->dev_addr); 1383257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_TXHADDR(0), td->haddr); 1384257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_TXHUBPORT(0), td->hport); 1385257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_TXTI, td->transfer_type); 1386257041Shselasky 1387257041Shselasky /* TX NAK timeout */ 1388257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_TXNAKLIMIT, MAX_NAK_TO); 1389257041Shselasky 1390257041Shselasky td->transaction_started = 1; 1391257041Shselasky 1392257041Shselasky /* write command */ 1393257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 1394257041Shselasky MUSB2_MASK_CSR0L_STATUSPKT | 1395257041Shselasky MUSB2_MASK_CSR0L_TXPKTRDY); 1396257041Shselasky 1397257041Shselasky return (1); /* wait for interrupt */ 1398257041Shselasky} 1399257041Shselasky 1400257041Shselaskystatic uint8_t 1401257041Shselaskymusbotg_dev_data_rx(struct musbotg_td *td) 1402257041Shselasky{ 1403192984Sthompsa struct usb_page_search buf_res; 1404184610Salfred struct musbotg_softc *sc; 1405184610Salfred uint16_t count; 1406184610Salfred uint8_t csr; 1407184610Salfred uint8_t to; 1408184610Salfred uint8_t got_short; 1409184610Salfred 1410184610Salfred to = 8; /* don't loop forever! */ 1411184610Salfred got_short = 0; 1412184610Salfred 1413184610Salfred /* get pointer to softc */ 1414184610Salfred sc = MUSBOTG_PC2SC(td->pc); 1415184610Salfred 1416257041Shselasky if (td->channel == -1) 1417257041Shselasky td->channel = musbotg_channel_alloc(sc, td); 1418257041Shselasky 1419257041Shselasky /* EP0 is busy, wait */ 1420257041Shselasky if (td->channel == -1) 1421257041Shselasky return (1); 1422257041Shselasky 1423184610Salfred /* select endpoint */ 1424257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_EPINDEX, td->channel); 1425184610Salfred 1426184610Salfredrepeat: 1427184610Salfred /* read out FIFO status */ 1428184610Salfred csr = MUSB2_READ_1(sc, MUSB2_REG_RXCSRL); 1429184610Salfred 1430184610Salfred DPRINTFN(4, "csr=0x%02x\n", csr); 1431184610Salfred 1432184610Salfred /* clear overrun */ 1433184610Salfred if (csr & MUSB2_MASK_CSRL_RXOVERRUN) { 1434184610Salfred /* make sure we don't clear "RXPKTRDY" */ 1435184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_RXCSRL, 1436184610Salfred MUSB2_MASK_CSRL_RXPKTRDY); 1437184610Salfred } 1438257041Shselasky 1439184610Salfred /* check status */ 1440257041Shselasky if (!(csr & MUSB2_MASK_CSRL_RXPKTRDY)) 1441257041Shselasky return (1); /* not complete */ 1442257041Shselasky 1443184610Salfred /* get the packet byte count */ 1444184610Salfred count = MUSB2_READ_2(sc, MUSB2_REG_RXCOUNT); 1445184610Salfred 1446184610Salfred DPRINTFN(4, "count=0x%04x\n", count); 1447184610Salfred 1448184610Salfred /* 1449184610Salfred * Check for short or invalid packet: 1450184610Salfred */ 1451184610Salfred if (count != td->max_frame_size) { 1452184610Salfred if (count < td->max_frame_size) { 1453184610Salfred /* we have a short packet */ 1454184610Salfred td->short_pkt = 1; 1455184610Salfred got_short = 1; 1456184610Salfred } else { 1457184610Salfred /* invalid USB packet */ 1458184610Salfred td->error = 1; 1459257041Shselasky musbotg_channel_free(sc, td); 1460184610Salfred return (0); /* we are complete */ 1461184610Salfred } 1462184610Salfred } 1463184610Salfred /* verify the packet byte count */ 1464184610Salfred if (count > td->remainder) { 1465184610Salfred /* invalid USB packet */ 1466184610Salfred td->error = 1; 1467257041Shselasky musbotg_channel_free(sc, td); 1468184610Salfred return (0); /* we are complete */ 1469184610Salfred } 1470184610Salfred while (count > 0) { 1471184610Salfred uint32_t temp; 1472184610Salfred 1473194228Sthompsa usbd_get_page(td->pc, td->offset, &buf_res); 1474184610Salfred 1475184610Salfred /* get correct length */ 1476184610Salfred if (buf_res.length > count) { 1477184610Salfred buf_res.length = count; 1478184610Salfred } 1479184610Salfred /* check for unaligned memory address */ 1480184610Salfred if (USB_P2U(buf_res.buffer) & 3) { 1481184610Salfred 1482184610Salfred temp = count & ~3; 1483184610Salfred 1484184610Salfred if (temp) { 1485184610Salfred /* receive data 4 bytes at a time */ 1486184610Salfred bus_space_read_multi_4(sc->sc_io_tag, sc->sc_io_hdl, 1487257041Shselasky MUSB2_REG_EPFIFO(td->channel), sc->sc_bounce_buf, 1488184610Salfred temp / 4); 1489184610Salfred } 1490184610Salfred temp = count & 3; 1491184610Salfred if (temp) { 1492184610Salfred /* receive data 1 byte at a time */ 1493184610Salfred bus_space_read_multi_1(sc->sc_io_tag, 1494257041Shselasky sc->sc_io_hdl, MUSB2_REG_EPFIFO(td->channel), 1495184610Salfred ((void *)&sc->sc_bounce_buf[count / 4]), temp); 1496184610Salfred } 1497194228Sthompsa usbd_copy_in(td->pc, td->offset, 1498184610Salfred sc->sc_bounce_buf, count); 1499184610Salfred 1500184610Salfred /* update offset and remainder */ 1501184610Salfred td->offset += count; 1502184610Salfred td->remainder -= count; 1503184610Salfred break; 1504184610Salfred } 1505184610Salfred /* check if we can optimise */ 1506184610Salfred if (buf_res.length >= 4) { 1507184610Salfred 1508184610Salfred /* receive data 4 bytes at a time */ 1509184610Salfred bus_space_read_multi_4(sc->sc_io_tag, sc->sc_io_hdl, 1510257041Shselasky MUSB2_REG_EPFIFO(td->channel), buf_res.buffer, 1511184610Salfred buf_res.length / 4); 1512184610Salfred 1513184610Salfred temp = buf_res.length & ~3; 1514184610Salfred 1515184610Salfred /* update counters */ 1516184610Salfred count -= temp; 1517184610Salfred td->offset += temp; 1518184610Salfred td->remainder -= temp; 1519184610Salfred continue; 1520184610Salfred } 1521184610Salfred /* receive data */ 1522184610Salfred bus_space_read_multi_1(sc->sc_io_tag, sc->sc_io_hdl, 1523257041Shselasky MUSB2_REG_EPFIFO(td->channel), buf_res.buffer, 1524184610Salfred buf_res.length); 1525184610Salfred 1526184610Salfred /* update counters */ 1527184610Salfred count -= buf_res.length; 1528184610Salfred td->offset += buf_res.length; 1529184610Salfred td->remainder -= buf_res.length; 1530184610Salfred } 1531184610Salfred 1532184610Salfred /* clear status bits */ 1533184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_RXCSRL, 0); 1534184610Salfred 1535184610Salfred /* check if we are complete */ 1536184610Salfred if ((td->remainder == 0) || got_short) { 1537184610Salfred if (td->short_pkt) { 1538184610Salfred /* we are complete */ 1539257041Shselasky musbotg_channel_free(sc, td); 1540184610Salfred return (0); 1541184610Salfred } 1542184610Salfred /* else need to receive a zero length packet */ 1543184610Salfred } 1544184610Salfred if (--to) { 1545184610Salfred goto repeat; 1546184610Salfred } 1547184610Salfred return (1); /* not complete */ 1548184610Salfred} 1549184610Salfred 1550184610Salfredstatic uint8_t 1551257041Shselaskymusbotg_dev_data_tx(struct musbotg_td *td) 1552184610Salfred{ 1553192984Sthompsa struct usb_page_search buf_res; 1554184610Salfred struct musbotg_softc *sc; 1555184610Salfred uint16_t count; 1556184610Salfred uint8_t csr; 1557184610Salfred uint8_t to; 1558184610Salfred 1559184610Salfred to = 8; /* don't loop forever! */ 1560184610Salfred 1561184610Salfred /* get pointer to softc */ 1562184610Salfred sc = MUSBOTG_PC2SC(td->pc); 1563184610Salfred 1564257041Shselasky if (td->channel == -1) 1565257041Shselasky td->channel = musbotg_channel_alloc(sc, td); 1566257041Shselasky 1567257041Shselasky /* EP0 is busy, wait */ 1568257041Shselasky if (td->channel == -1) 1569257041Shselasky return (1); 1570257041Shselasky 1571184610Salfred /* select endpoint */ 1572257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_EPINDEX, td->channel); 1573184610Salfred 1574184610Salfredrepeat: 1575184610Salfred 1576184610Salfred /* read out FIFO status */ 1577184610Salfred csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL); 1578184610Salfred 1579184610Salfred DPRINTFN(4, "csr=0x%02x\n", csr); 1580184610Salfred 1581184610Salfred if (csr & (MUSB2_MASK_CSRL_TXINCOMP | 1582184610Salfred MUSB2_MASK_CSRL_TXUNDERRUN)) { 1583184610Salfred /* clear status bits */ 1584184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 0); 1585184610Salfred } 1586184610Salfred if (csr & MUSB2_MASK_CSRL_TXPKTRDY) { 1587184610Salfred return (1); /* not complete */ 1588184610Salfred } 1589184610Salfred /* check for short packet */ 1590184610Salfred count = td->max_frame_size; 1591184610Salfred if (td->remainder < count) { 1592184610Salfred /* we have a short packet */ 1593184610Salfred td->short_pkt = 1; 1594184610Salfred count = td->remainder; 1595184610Salfred } 1596184610Salfred while (count > 0) { 1597184610Salfred uint32_t temp; 1598184610Salfred 1599194228Sthompsa usbd_get_page(td->pc, td->offset, &buf_res); 1600184610Salfred 1601184610Salfred /* get correct length */ 1602184610Salfred if (buf_res.length > count) { 1603184610Salfred buf_res.length = count; 1604184610Salfred } 1605184610Salfred /* check for unaligned memory address */ 1606184610Salfred if (USB_P2U(buf_res.buffer) & 3) { 1607184610Salfred 1608194228Sthompsa usbd_copy_out(td->pc, td->offset, 1609184610Salfred sc->sc_bounce_buf, count); 1610184610Salfred 1611184610Salfred temp = count & ~3; 1612184610Salfred 1613184610Salfred if (temp) { 1614184610Salfred /* transmit data 4 bytes at a time */ 1615184610Salfred bus_space_write_multi_4(sc->sc_io_tag, 1616257041Shselasky sc->sc_io_hdl, MUSB2_REG_EPFIFO(td->channel), 1617184610Salfred sc->sc_bounce_buf, temp / 4); 1618184610Salfred } 1619184610Salfred temp = count & 3; 1620184610Salfred if (temp) { 1621184610Salfred /* receive data 1 byte at a time */ 1622184610Salfred bus_space_write_multi_1(sc->sc_io_tag, sc->sc_io_hdl, 1623257041Shselasky MUSB2_REG_EPFIFO(td->channel), 1624184610Salfred ((void *)&sc->sc_bounce_buf[count / 4]), temp); 1625184610Salfred } 1626184610Salfred /* update offset and remainder */ 1627184610Salfred td->offset += count; 1628184610Salfred td->remainder -= count; 1629184610Salfred break; 1630184610Salfred } 1631184610Salfred /* check if we can optimise */ 1632184610Salfred if (buf_res.length >= 4) { 1633184610Salfred 1634184610Salfred /* transmit data 4 bytes at a time */ 1635184610Salfred bus_space_write_multi_4(sc->sc_io_tag, sc->sc_io_hdl, 1636257041Shselasky MUSB2_REG_EPFIFO(td->channel), buf_res.buffer, 1637184610Salfred buf_res.length / 4); 1638184610Salfred 1639184610Salfred temp = buf_res.length & ~3; 1640184610Salfred 1641184610Salfred /* update counters */ 1642184610Salfred count -= temp; 1643184610Salfred td->offset += temp; 1644184610Salfred td->remainder -= temp; 1645184610Salfred continue; 1646184610Salfred } 1647184610Salfred /* transmit data */ 1648184610Salfred bus_space_write_multi_1(sc->sc_io_tag, sc->sc_io_hdl, 1649257041Shselasky MUSB2_REG_EPFIFO(td->channel), buf_res.buffer, 1650184610Salfred buf_res.length); 1651184610Salfred 1652184610Salfred /* update counters */ 1653184610Salfred count -= buf_res.length; 1654184610Salfred td->offset += buf_res.length; 1655184610Salfred td->remainder -= buf_res.length; 1656184610Salfred } 1657184610Salfred 1658257041Shselasky /* Max packet size */ 1659257041Shselasky MUSB2_WRITE_2(sc, MUSB2_REG_TXMAXP, td->reg_max_packet); 1660257041Shselasky 1661184610Salfred /* write command */ 1662184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 1663184610Salfred MUSB2_MASK_CSRL_TXPKTRDY); 1664184610Salfred 1665184610Salfred /* check remainder */ 1666184610Salfred if (td->remainder == 0) { 1667184610Salfred if (td->short_pkt) { 1668257041Shselasky musbotg_channel_free(sc, td); 1669184610Salfred return (0); /* complete */ 1670184610Salfred } 1671184610Salfred /* else we need to transmit a short packet */ 1672184610Salfred } 1673184610Salfred if (--to) { 1674184610Salfred goto repeat; 1675184610Salfred } 1676184610Salfred return (1); /* not complete */ 1677184610Salfred} 1678184610Salfred 1679184610Salfredstatic uint8_t 1680257041Shselaskymusbotg_host_data_rx(struct musbotg_td *td) 1681257041Shselasky{ 1682257041Shselasky struct usb_page_search buf_res; 1683257041Shselasky struct musbotg_softc *sc; 1684257041Shselasky uint16_t count; 1685257041Shselasky uint8_t csr, csrh; 1686257041Shselasky uint8_t to; 1687257041Shselasky uint8_t got_short; 1688257041Shselasky 1689257041Shselasky /* get pointer to softc */ 1690257041Shselasky sc = MUSBOTG_PC2SC(td->pc); 1691257041Shselasky 1692257041Shselasky if (td->channel == -1) 1693257041Shselasky td->channel = musbotg_channel_alloc(sc, td); 1694257041Shselasky 1695257041Shselasky /* No free EPs */ 1696257041Shselasky if (td->channel == -1) 1697257041Shselasky return (1); 1698257041Shselasky 1699257041Shselasky DPRINTFN(1, "ep_no=%d\n", td->channel); 1700257041Shselasky 1701257041Shselasky to = 8; /* don't loop forever! */ 1702257041Shselasky got_short = 0; 1703257041Shselasky 1704257041Shselasky /* select endpoint */ 1705257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_EPINDEX, td->channel); 1706257041Shselasky 1707257041Shselaskyrepeat: 1708257041Shselasky /* read out FIFO status */ 1709257041Shselasky csr = MUSB2_READ_1(sc, MUSB2_REG_RXCSRL); 1710257041Shselasky DPRINTFN(4, "csr=0x%02x\n", csr); 1711257041Shselasky 1712257041Shselasky if (!td->transaction_started) { 1713257041Shselasky /* Function address */ 1714257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_RXFADDR(td->channel), 1715257041Shselasky td->dev_addr); 1716257041Shselasky 1717257041Shselasky /* SPLIT transaction */ 1718257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_RXHADDR(td->channel), 1719257041Shselasky td->haddr); 1720257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_RXHUBPORT(td->channel), 1721257041Shselasky td->hport); 1722257041Shselasky 1723257041Shselasky /* RX NAK timeout */ 1724257041Shselasky if (td->transfer_type & MUSB2_MASK_TI_PROTO_ISOC) 1725257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_RXNAKLIMIT, 0); 1726257041Shselasky else 1727257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_RXNAKLIMIT, MAX_NAK_TO); 1728257041Shselasky 1729257041Shselasky /* Protocol, speed, device endpoint */ 1730257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_RXTI, td->transfer_type); 1731257041Shselasky 1732257041Shselasky /* Max packet size */ 1733257041Shselasky MUSB2_WRITE_2(sc, MUSB2_REG_RXMAXP, td->reg_max_packet); 1734257041Shselasky 1735257041Shselasky /* Data Toggle */ 1736257041Shselasky csrh = MUSB2_READ_1(sc, MUSB2_REG_RXCSRH); 1737257041Shselasky DPRINTFN(4, "csrh=0x%02x\n", csrh); 1738257041Shselasky 1739257041Shselasky csrh |= MUSB2_MASK_CSRH_RXDT_WREN; 1740257041Shselasky if (td->toggle) 1741257041Shselasky csrh |= MUSB2_MASK_CSRH_RXDT_VAL; 1742257041Shselasky else 1743257041Shselasky csrh &= ~MUSB2_MASK_CSRH_RXDT_VAL; 1744257041Shselasky 1745257041Shselasky /* Set data toggle */ 1746257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_RXCSRH, csrh); 1747257041Shselasky 1748257041Shselasky /* write command */ 1749257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_RXCSRL, 1750257041Shselasky MUSB2_MASK_CSRL_RXREQPKT); 1751257041Shselasky 1752257041Shselasky td->transaction_started = 1; 1753257041Shselasky return (1); 1754257041Shselasky } 1755257041Shselasky 1756257041Shselasky /* clear NAK timeout */ 1757257041Shselasky if (csr & MUSB2_MASK_CSRL_RXNAKTO) { 1758257041Shselasky DPRINTFN(4, "NAK Timeout\n"); 1759257041Shselasky if (csr & MUSB2_MASK_CSRL_RXREQPKT) { 1760257041Shselasky csr &= ~MUSB2_MASK_CSRL_RXREQPKT; 1761257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_RXCSRL, csr); 1762257041Shselasky 1763257041Shselasky csr &= ~MUSB2_MASK_CSRL_RXNAKTO; 1764257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_RXCSRL, csr); 1765257041Shselasky } 1766257041Shselasky 1767257041Shselasky td->error = 1; 1768257041Shselasky } 1769257041Shselasky 1770257041Shselasky if (csr & MUSB2_MASK_CSRL_RXERROR) { 1771257041Shselasky DPRINTFN(4, "RXERROR\n"); 1772257041Shselasky td->error = 1; 1773257041Shselasky } 1774257041Shselasky 1775257041Shselasky if (csr & MUSB2_MASK_CSRL_RXSTALL) { 1776257041Shselasky DPRINTFN(4, "RXSTALL\n"); 1777257041Shselasky td->error = 1; 1778257041Shselasky } 1779257041Shselasky 1780257041Shselasky if (td->error) { 1781257041Shselasky musbotg_channel_free(sc, td); 1782257041Shselasky return (0); /* we are complete */ 1783257041Shselasky } 1784257041Shselasky 1785257041Shselasky if (!(csr & MUSB2_MASK_CSRL_RXPKTRDY)) { 1786257041Shselasky /* No data available yet */ 1787257041Shselasky return (1); 1788257041Shselasky } 1789257041Shselasky 1790257041Shselasky td->toggle ^= 1; 1791257041Shselasky /* get the packet byte count */ 1792257041Shselasky count = MUSB2_READ_2(sc, MUSB2_REG_RXCOUNT); 1793257041Shselasky DPRINTFN(4, "count=0x%04x\n", count); 1794257041Shselasky 1795257041Shselasky /* 1796257041Shselasky * Check for short or invalid packet: 1797257041Shselasky */ 1798257041Shselasky if (count != td->max_frame_size) { 1799257041Shselasky if (count < td->max_frame_size) { 1800257041Shselasky /* we have a short packet */ 1801257041Shselasky td->short_pkt = 1; 1802257041Shselasky got_short = 1; 1803257041Shselasky } else { 1804257041Shselasky /* invalid USB packet */ 1805257041Shselasky td->error = 1; 1806257041Shselasky musbotg_channel_free(sc, td); 1807257041Shselasky return (0); /* we are complete */ 1808257041Shselasky } 1809257041Shselasky } 1810257041Shselasky 1811257041Shselasky /* verify the packet byte count */ 1812257041Shselasky if (count > td->remainder) { 1813257041Shselasky /* invalid USB packet */ 1814257041Shselasky td->error = 1; 1815257041Shselasky musbotg_channel_free(sc, td); 1816257041Shselasky return (0); /* we are complete */ 1817257041Shselasky } 1818257041Shselasky 1819257041Shselasky while (count > 0) { 1820257041Shselasky uint32_t temp; 1821257041Shselasky 1822257041Shselasky usbd_get_page(td->pc, td->offset, &buf_res); 1823257041Shselasky 1824257041Shselasky /* get correct length */ 1825257041Shselasky if (buf_res.length > count) { 1826257041Shselasky buf_res.length = count; 1827257041Shselasky } 1828257041Shselasky /* check for unaligned memory address */ 1829257041Shselasky if (USB_P2U(buf_res.buffer) & 3) { 1830257041Shselasky 1831257041Shselasky temp = count & ~3; 1832257041Shselasky 1833257041Shselasky if (temp) { 1834257041Shselasky /* receive data 4 bytes at a time */ 1835257041Shselasky bus_space_read_multi_4(sc->sc_io_tag, sc->sc_io_hdl, 1836257041Shselasky MUSB2_REG_EPFIFO(td->channel), sc->sc_bounce_buf, 1837257041Shselasky temp / 4); 1838257041Shselasky } 1839257041Shselasky temp = count & 3; 1840257041Shselasky if (temp) { 1841257041Shselasky /* receive data 1 byte at a time */ 1842257041Shselasky bus_space_read_multi_1(sc->sc_io_tag, 1843257041Shselasky sc->sc_io_hdl, MUSB2_REG_EPFIFO(td->channel), 1844257041Shselasky ((void *)&sc->sc_bounce_buf[count / 4]), temp); 1845257041Shselasky } 1846257041Shselasky usbd_copy_in(td->pc, td->offset, 1847257041Shselasky sc->sc_bounce_buf, count); 1848257041Shselasky 1849257041Shselasky /* update offset and remainder */ 1850257041Shselasky td->offset += count; 1851257041Shselasky td->remainder -= count; 1852257041Shselasky break; 1853257041Shselasky } 1854257041Shselasky /* check if we can optimise */ 1855257041Shselasky if (buf_res.length >= 4) { 1856257041Shselasky 1857257041Shselasky /* receive data 4 bytes at a time */ 1858257041Shselasky bus_space_read_multi_4(sc->sc_io_tag, sc->sc_io_hdl, 1859257041Shselasky MUSB2_REG_EPFIFO(td->channel), buf_res.buffer, 1860257041Shselasky buf_res.length / 4); 1861257041Shselasky 1862257041Shselasky temp = buf_res.length & ~3; 1863257041Shselasky 1864257041Shselasky /* update counters */ 1865257041Shselasky count -= temp; 1866257041Shselasky td->offset += temp; 1867257041Shselasky td->remainder -= temp; 1868257041Shselasky continue; 1869257041Shselasky } 1870257041Shselasky /* receive data */ 1871257041Shselasky bus_space_read_multi_1(sc->sc_io_tag, sc->sc_io_hdl, 1872257041Shselasky MUSB2_REG_EPFIFO(td->channel), buf_res.buffer, 1873257041Shselasky buf_res.length); 1874257041Shselasky 1875257041Shselasky /* update counters */ 1876257041Shselasky count -= buf_res.length; 1877257041Shselasky td->offset += buf_res.length; 1878257041Shselasky td->remainder -= buf_res.length; 1879257041Shselasky } 1880257041Shselasky 1881257041Shselasky /* clear status bits */ 1882257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_RXCSRL, 0); 1883257041Shselasky 1884257041Shselasky /* check if we are complete */ 1885257041Shselasky if ((td->remainder == 0) || got_short) { 1886257041Shselasky if (td->short_pkt) { 1887257041Shselasky /* we are complete */ 1888257041Shselasky musbotg_channel_free(sc, td); 1889257041Shselasky return (0); 1890257041Shselasky } 1891257041Shselasky /* else need to receive a zero length packet */ 1892257041Shselasky } 1893257041Shselasky 1894257041Shselasky /* Reset transaction state and restart */ 1895257041Shselasky td->transaction_started = 0; 1896257041Shselasky 1897257041Shselasky if (--to) 1898257041Shselasky goto repeat; 1899257041Shselasky 1900257041Shselasky return (1); /* not complete */ 1901257041Shselasky} 1902257041Shselasky 1903257041Shselaskystatic uint8_t 1904257041Shselaskymusbotg_host_data_tx(struct musbotg_td *td) 1905257041Shselasky{ 1906257041Shselasky struct usb_page_search buf_res; 1907257041Shselasky struct musbotg_softc *sc; 1908257041Shselasky uint16_t count; 1909257041Shselasky uint8_t csr, csrh; 1910257041Shselasky 1911257041Shselasky /* get pointer to softc */ 1912257041Shselasky sc = MUSBOTG_PC2SC(td->pc); 1913257041Shselasky 1914257041Shselasky if (td->channel == -1) 1915257041Shselasky td->channel = musbotg_channel_alloc(sc, td); 1916257041Shselasky 1917257041Shselasky /* No free EPs */ 1918257041Shselasky if (td->channel == -1) 1919257041Shselasky return (1); 1920257041Shselasky 1921257041Shselasky DPRINTFN(1, "ep_no=%d\n", td->channel); 1922257041Shselasky 1923257041Shselasky /* select endpoint */ 1924257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_EPINDEX, td->channel); 1925257041Shselasky 1926257041Shselasky /* read out FIFO status */ 1927257041Shselasky csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL); 1928257041Shselasky DPRINTFN(4, "csr=0x%02x\n", csr); 1929257041Shselasky 1930257041Shselasky if (csr & (MUSB2_MASK_CSRL_TXSTALLED | 1931257041Shselasky MUSB2_MASK_CSRL_TXERROR)) { 1932257041Shselasky /* clear status bits */ 1933257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 0); 1934257041Shselasky td->error = 1; 1935257041Shselasky musbotg_channel_free(sc, td); 1936257041Shselasky return (0); /* complete */ 1937257041Shselasky } 1938257041Shselasky 1939257041Shselasky if (csr & MUSB2_MASK_CSRL_TXNAKTO) { 1940257041Shselasky /* 1941257041Shselasky * Flush TX FIFO before clearing NAK TO 1942257041Shselasky */ 1943257041Shselasky if (csr & MUSB2_MASK_CSRL_TXFIFONEMPTY) { 1944257041Shselasky csr |= MUSB2_MASK_CSRL_TXFFLUSH; 1945257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, csr); 1946257041Shselasky csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL); 1947257041Shselasky if (csr & MUSB2_MASK_CSRL_TXFIFONEMPTY) { 1948257041Shselasky csr |= MUSB2_MASK_CSRL_TXFFLUSH; 1949257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, csr); 1950257041Shselasky csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL); 1951257041Shselasky } 1952257041Shselasky } 1953257041Shselasky 1954257041Shselasky csr &= ~MUSB2_MASK_CSRL_TXNAKTO; 1955257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, csr); 1956257041Shselasky 1957257041Shselasky td->error = 1; 1958257041Shselasky musbotg_channel_free(sc, td); 1959257041Shselasky return (0); /* complete */ 1960257041Shselasky } 1961257041Shselasky 1962257041Shselasky /* 1963257041Shselasky * Wait while FIFO is empty. 1964257041Shselasky * Do not flush it because it will cause transactions 1965257041Shselasky * with size more then packet size. It might upset 1966257041Shselasky * some devices 1967257041Shselasky */ 1968257041Shselasky if (csr & MUSB2_MASK_CSRL_TXFIFONEMPTY) 1969257041Shselasky return (1); 1970257041Shselasky 1971257041Shselasky /* Packet still being processed */ 1972257041Shselasky if (csr & MUSB2_MASK_CSRL_TXPKTRDY) 1973257041Shselasky return (1); 1974257041Shselasky 1975257041Shselasky if (td->transaction_started) { 1976257041Shselasky /* check remainder */ 1977257041Shselasky if (td->remainder == 0) { 1978257041Shselasky if (td->short_pkt) { 1979257041Shselasky musbotg_channel_free(sc, td); 1980257041Shselasky return (0); /* complete */ 1981257041Shselasky } 1982257041Shselasky /* else we need to transmit a short packet */ 1983257041Shselasky } 1984257041Shselasky 1985257041Shselasky /* We're not complete - more transactions required */ 1986257041Shselasky td->transaction_started = 0; 1987257041Shselasky } 1988257041Shselasky 1989257041Shselasky /* check for short packet */ 1990257041Shselasky count = td->max_frame_size; 1991257041Shselasky if (td->remainder < count) { 1992257041Shselasky /* we have a short packet */ 1993257041Shselasky td->short_pkt = 1; 1994257041Shselasky count = td->remainder; 1995257041Shselasky } 1996257041Shselasky 1997257041Shselasky while (count > 0) { 1998257041Shselasky uint32_t temp; 1999257041Shselasky 2000257041Shselasky usbd_get_page(td->pc, td->offset, &buf_res); 2001257041Shselasky 2002257041Shselasky /* get correct length */ 2003257041Shselasky if (buf_res.length > count) { 2004257041Shselasky buf_res.length = count; 2005257041Shselasky } 2006257041Shselasky /* check for unaligned memory address */ 2007257041Shselasky if (USB_P2U(buf_res.buffer) & 3) { 2008257041Shselasky 2009257041Shselasky usbd_copy_out(td->pc, td->offset, 2010257041Shselasky sc->sc_bounce_buf, count); 2011257041Shselasky 2012257041Shselasky temp = count & ~3; 2013257041Shselasky 2014257041Shselasky if (temp) { 2015257041Shselasky /* transmit data 4 bytes at a time */ 2016257041Shselasky bus_space_write_multi_4(sc->sc_io_tag, 2017257041Shselasky sc->sc_io_hdl, MUSB2_REG_EPFIFO(td->channel), 2018257041Shselasky sc->sc_bounce_buf, temp / 4); 2019257041Shselasky } 2020257041Shselasky temp = count & 3; 2021257041Shselasky if (temp) { 2022257041Shselasky /* receive data 1 byte at a time */ 2023257041Shselasky bus_space_write_multi_1(sc->sc_io_tag, sc->sc_io_hdl, 2024257041Shselasky MUSB2_REG_EPFIFO(td->channel), 2025257041Shselasky ((void *)&sc->sc_bounce_buf[count / 4]), temp); 2026257041Shselasky } 2027257041Shselasky /* update offset and remainder */ 2028257041Shselasky td->offset += count; 2029257041Shselasky td->remainder -= count; 2030257041Shselasky break; 2031257041Shselasky } 2032257041Shselasky /* check if we can optimise */ 2033257041Shselasky if (buf_res.length >= 4) { 2034257041Shselasky 2035257041Shselasky /* transmit data 4 bytes at a time */ 2036257041Shselasky bus_space_write_multi_4(sc->sc_io_tag, sc->sc_io_hdl, 2037257041Shselasky MUSB2_REG_EPFIFO(td->channel), buf_res.buffer, 2038257041Shselasky buf_res.length / 4); 2039257041Shselasky 2040257041Shselasky temp = buf_res.length & ~3; 2041257041Shselasky 2042257041Shselasky /* update counters */ 2043257041Shselasky count -= temp; 2044257041Shselasky td->offset += temp; 2045257041Shselasky td->remainder -= temp; 2046257041Shselasky continue; 2047257041Shselasky } 2048257041Shselasky /* transmit data */ 2049257041Shselasky bus_space_write_multi_1(sc->sc_io_tag, sc->sc_io_hdl, 2050257041Shselasky MUSB2_REG_EPFIFO(td->channel), buf_res.buffer, 2051257041Shselasky buf_res.length); 2052257041Shselasky 2053257041Shselasky /* update counters */ 2054257041Shselasky count -= buf_res.length; 2055257041Shselasky td->offset += buf_res.length; 2056257041Shselasky td->remainder -= buf_res.length; 2057257041Shselasky } 2058257041Shselasky 2059257041Shselasky /* Function address */ 2060257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_TXFADDR(td->channel), 2061257041Shselasky td->dev_addr); 2062257041Shselasky 2063257041Shselasky /* SPLIT transaction */ 2064257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_TXHADDR(td->channel), 2065257041Shselasky td->haddr); 2066257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_TXHUBPORT(td->channel), 2067257041Shselasky td->hport); 2068257041Shselasky 2069257041Shselasky /* TX NAK timeout */ 2070257041Shselasky if (td->transfer_type & MUSB2_MASK_TI_PROTO_ISOC) 2071257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_TXNAKLIMIT, 0); 2072257041Shselasky else 2073257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_TXNAKLIMIT, MAX_NAK_TO); 2074257041Shselasky 2075257041Shselasky /* Protocol, speed, device endpoint */ 2076257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_TXTI, td->transfer_type); 2077257041Shselasky 2078257041Shselasky /* Max packet size */ 2079257041Shselasky MUSB2_WRITE_2(sc, MUSB2_REG_TXMAXP, td->reg_max_packet); 2080257041Shselasky 2081257041Shselasky if (!td->transaction_started) { 2082257041Shselasky csrh = MUSB2_READ_1(sc, MUSB2_REG_TXCSRH); 2083257041Shselasky DPRINTFN(4, "csrh=0x%02x\n", csrh); 2084257041Shselasky 2085257041Shselasky csrh |= MUSB2_MASK_CSRH_TXDT_WREN; 2086257041Shselasky if (td->toggle) 2087257041Shselasky csrh |= MUSB2_MASK_CSRH_TXDT_VAL; 2088257041Shselasky else 2089257041Shselasky csrh &= ~MUSB2_MASK_CSRH_TXDT_VAL; 2090257041Shselasky 2091257041Shselasky /* Set data toggle */ 2092257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRH, csrh); 2093257041Shselasky } 2094257041Shselasky 2095257041Shselasky /* write command */ 2096257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 2097257041Shselasky MUSB2_MASK_CSRL_TXPKTRDY); 2098257041Shselasky 2099257041Shselasky /* Update Data Toggle */ 2100257041Shselasky td->toggle ^= 1; 2101257041Shselasky td->transaction_started = 1; 2102257041Shselasky 2103257041Shselasky return (1); /* not complete */ 2104257041Shselasky} 2105257041Shselasky 2106257041Shselaskystatic uint8_t 2107192984Sthompsamusbotg_xfer_do_fifo(struct usb_xfer *xfer) 2108184610Salfred{ 2109184610Salfred struct musbotg_softc *sc; 2110184610Salfred struct musbotg_td *td; 2111184610Salfred 2112184610Salfred DPRINTFN(8, "\n"); 2113257041Shselasky sc = MUSBOTG_BUS2SC(xfer->xroot->bus); 2114184610Salfred 2115184610Salfred td = xfer->td_transfer_cache; 2116184610Salfred while (1) { 2117257041Shselasky 2118184610Salfred if ((td->func) (td)) { 2119184610Salfred /* operation in progress */ 2120184610Salfred break; 2121184610Salfred } 2122257041Shselasky 2123184610Salfred if (((void *)td) == xfer->td_transfer_last) { 2124184610Salfred goto done; 2125184610Salfred } 2126184610Salfred if (td->error) { 2127184610Salfred goto done; 2128184610Salfred } else if (td->remainder > 0) { 2129184610Salfred /* 2130184610Salfred * We had a short transfer. If there is no alternate 2131184610Salfred * next, stop processing ! 2132184610Salfred */ 2133184610Salfred if (!td->alt_next) { 2134184610Salfred goto done; 2135184610Salfred } 2136184610Salfred } 2137184610Salfred /* 2138184610Salfred * Fetch the next transfer descriptor and transfer 2139184610Salfred * some flags to the next transfer descriptor 2140184610Salfred */ 2141184610Salfred td = td->obj_next; 2142184610Salfred xfer->td_transfer_cache = td; 2143184610Salfred } 2144257041Shselasky 2145184610Salfred return (1); /* not complete */ 2146184610Salfreddone: 2147184610Salfred /* compute all actual lengths */ 2148184610Salfred musbotg_standard_done(xfer); 2149184610Salfred 2150184610Salfred return (0); /* complete */ 2151184610Salfred} 2152184610Salfred 2153184610Salfredstatic void 2154184610Salfredmusbotg_interrupt_poll(struct musbotg_softc *sc) 2155184610Salfred{ 2156192984Sthompsa struct usb_xfer *xfer; 2157184610Salfred 2158184610Salfredrepeat: 2159184610Salfred TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) { 2160184610Salfred if (!musbotg_xfer_do_fifo(xfer)) { 2161184610Salfred /* queue has been modified */ 2162184610Salfred goto repeat; 2163184610Salfred } 2164184610Salfred } 2165184610Salfred} 2166184610Salfred 2167187175Sthompsavoid 2168187175Sthompsamusbotg_vbus_interrupt(struct musbotg_softc *sc, uint8_t is_on) 2169184610Salfred{ 2170184610Salfred DPRINTFN(4, "vbus = %u\n", is_on); 2171184610Salfred 2172184824Sthompsa USB_BUS_LOCK(&sc->sc_bus); 2173184610Salfred if (is_on) { 2174184610Salfred if (!sc->sc_flags.status_vbus) { 2175184610Salfred sc->sc_flags.status_vbus = 1; 2176184610Salfred 2177184610Salfred /* complete root HUB interrupt endpoint */ 2178190735Sthompsa musbotg_root_intr(sc); 2179184610Salfred } 2180184610Salfred } else { 2181184610Salfred if (sc->sc_flags.status_vbus) { 2182184610Salfred sc->sc_flags.status_vbus = 0; 2183184610Salfred sc->sc_flags.status_bus_reset = 0; 2184184610Salfred sc->sc_flags.status_suspend = 0; 2185184610Salfred sc->sc_flags.change_suspend = 0; 2186184610Salfred sc->sc_flags.change_connect = 1; 2187184610Salfred 2188184610Salfred /* complete root HUB interrupt endpoint */ 2189190735Sthompsa musbotg_root_intr(sc); 2190184610Salfred } 2191184610Salfred } 2192184610Salfred 2193184824Sthompsa USB_BUS_UNLOCK(&sc->sc_bus); 2194184610Salfred} 2195184610Salfred 2196184610Salfredvoid 2197257041Shselaskymusbotg_connect_interrupt(struct musbotg_softc *sc) 2198184610Salfred{ 2199257041Shselasky USB_BUS_LOCK(&sc->sc_bus); 2200257041Shselasky sc->sc_flags.change_connect = 1; 2201257041Shselasky 2202257041Shselasky /* complete root HUB interrupt endpoint */ 2203257041Shselasky musbotg_root_intr(sc); 2204257041Shselasky USB_BUS_UNLOCK(&sc->sc_bus); 2205257041Shselasky} 2206257041Shselasky 2207257041Shselaskyvoid 2208257041Shselaskymusbotg_interrupt(struct musbotg_softc *sc, 2209257041Shselasky uint16_t rxstat, uint16_t txstat, uint8_t stat) 2210257041Shselasky{ 2211184610Salfred uint16_t rx_status; 2212184610Salfred uint16_t tx_status; 2213184610Salfred uint8_t usb_status; 2214184610Salfred uint8_t temp; 2215184610Salfred uint8_t to = 2; 2216184610Salfred 2217184824Sthompsa USB_BUS_LOCK(&sc->sc_bus); 2218184610Salfred 2219184610Salfredrepeat: 2220184610Salfred 2221184610Salfred /* read all interrupt registers */ 2222184610Salfred usb_status = MUSB2_READ_1(sc, MUSB2_REG_INTUSB); 2223184610Salfred 2224184610Salfred /* read all FIFO interrupts */ 2225184610Salfred rx_status = MUSB2_READ_2(sc, MUSB2_REG_INTRX); 2226184610Salfred tx_status = MUSB2_READ_2(sc, MUSB2_REG_INTTX); 2227257041Shselasky rx_status |= rxstat; 2228257041Shselasky tx_status |= txstat; 2229257041Shselasky usb_status |= stat; 2230184610Salfred 2231257041Shselasky /* Clear platform flags after first time */ 2232257041Shselasky rxstat = 0; 2233257041Shselasky txstat = 0; 2234257041Shselasky stat = 0; 2235257041Shselasky 2236184610Salfred /* check for any bus state change interrupts */ 2237184610Salfred 2238184610Salfred if (usb_status & (MUSB2_MASK_IRESET | 2239257041Shselasky MUSB2_MASK_IRESUME | MUSB2_MASK_ISUSP | 2240257041Shselasky MUSB2_MASK_ICONN | MUSB2_MASK_IDISC)) { 2241184610Salfred 2242184610Salfred DPRINTFN(4, "real bus interrupt 0x%08x\n", usb_status); 2243184610Salfred 2244184610Salfred if (usb_status & MUSB2_MASK_IRESET) { 2245184610Salfred 2246184610Salfred /* set correct state */ 2247184610Salfred sc->sc_flags.status_bus_reset = 1; 2248184610Salfred sc->sc_flags.status_suspend = 0; 2249184610Salfred sc->sc_flags.change_suspend = 0; 2250184610Salfred sc->sc_flags.change_connect = 1; 2251184610Salfred 2252184610Salfred /* determine line speed */ 2253184610Salfred temp = MUSB2_READ_1(sc, MUSB2_REG_POWER); 2254184610Salfred if (temp & MUSB2_MASK_HSMODE) 2255184610Salfred sc->sc_flags.status_high_speed = 1; 2256184610Salfred else 2257184610Salfred sc->sc_flags.status_high_speed = 0; 2258184610Salfred 2259184610Salfred /* 2260184610Salfred * After reset all interrupts are on and we need to 2261184610Salfred * turn them off! 2262184610Salfred */ 2263184610Salfred temp = MUSB2_MASK_IRESET; 2264184610Salfred /* disable resume interrupt */ 2265184610Salfred temp &= ~MUSB2_MASK_IRESUME; 2266184610Salfred /* enable suspend interrupt */ 2267184610Salfred temp |= MUSB2_MASK_ISUSP; 2268184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_INTUSBE, temp); 2269184610Salfred /* disable TX and RX interrupts */ 2270184610Salfred MUSB2_WRITE_2(sc, MUSB2_REG_INTTXE, 0); 2271184610Salfred MUSB2_WRITE_2(sc, MUSB2_REG_INTRXE, 0); 2272184610Salfred } 2273184610Salfred /* 2274184610Salfred * If RXRSM and RXSUSP is set at the same time we interpret 2275184610Salfred * that like RESUME. Resume is set when there is at least 3 2276184610Salfred * milliseconds of inactivity on the USB BUS. 2277184610Salfred */ 2278184610Salfred if (usb_status & MUSB2_MASK_IRESUME) { 2279184610Salfred if (sc->sc_flags.status_suspend) { 2280184610Salfred sc->sc_flags.status_suspend = 0; 2281184610Salfred sc->sc_flags.change_suspend = 1; 2282184610Salfred 2283184610Salfred temp = MUSB2_READ_1(sc, MUSB2_REG_INTUSBE); 2284184610Salfred /* disable resume interrupt */ 2285184610Salfred temp &= ~MUSB2_MASK_IRESUME; 2286184610Salfred /* enable suspend interrupt */ 2287184610Salfred temp |= MUSB2_MASK_ISUSP; 2288184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_INTUSBE, temp); 2289184610Salfred } 2290184610Salfred } else if (usb_status & MUSB2_MASK_ISUSP) { 2291184610Salfred if (!sc->sc_flags.status_suspend) { 2292184610Salfred sc->sc_flags.status_suspend = 1; 2293184610Salfred sc->sc_flags.change_suspend = 1; 2294184610Salfred 2295184610Salfred temp = MUSB2_READ_1(sc, MUSB2_REG_INTUSBE); 2296184610Salfred /* disable suspend interrupt */ 2297184610Salfred temp &= ~MUSB2_MASK_ISUSP; 2298184610Salfred /* enable resume interrupt */ 2299184610Salfred temp |= MUSB2_MASK_IRESUME; 2300184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_INTUSBE, temp); 2301184610Salfred } 2302184610Salfred } 2303257041Shselasky if (usb_status & 2304257041Shselasky (MUSB2_MASK_ICONN | MUSB2_MASK_IDISC)) 2305257041Shselasky sc->sc_flags.change_connect = 1; 2306257041Shselasky 2307257041Shselasky /* 2308257041Shselasky * Host Mode: There is no IRESET so assume bus is 2309257041Shselasky * always in reset state once device is connected. 2310257041Shselasky */ 2311257041Shselasky if (sc->sc_mode == MUSB2_HOST_MODE) { 2312257041Shselasky if (usb_status & MUSB2_MASK_ICONN) 2313257041Shselasky sc->sc_flags.status_bus_reset = 1; 2314257041Shselasky if (usb_status & MUSB2_MASK_IDISC) 2315257041Shselasky sc->sc_flags.status_bus_reset = 0; 2316257041Shselasky } 2317257041Shselasky 2318184610Salfred /* complete root HUB interrupt endpoint */ 2319190735Sthompsa musbotg_root_intr(sc); 2320184610Salfred } 2321184610Salfred /* check for any endpoint interrupts */ 2322184610Salfred 2323184610Salfred if (rx_status || tx_status) { 2324184610Salfred DPRINTFN(4, "real endpoint interrupt " 2325184610Salfred "rx=0x%04x, tx=0x%04x\n", rx_status, tx_status); 2326184610Salfred } 2327184610Salfred /* poll one time regardless of FIFO status */ 2328184610Salfred 2329184610Salfred musbotg_interrupt_poll(sc); 2330184610Salfred 2331184610Salfred if (--to) 2332184610Salfred goto repeat; 2333184610Salfred 2334184824Sthompsa USB_BUS_UNLOCK(&sc->sc_bus); 2335184610Salfred} 2336184610Salfred 2337184610Salfredstatic void 2338184610Salfredmusbotg_setup_standard_chain_sub(struct musbotg_std_temp *temp) 2339184610Salfred{ 2340184610Salfred struct musbotg_td *td; 2341184610Salfred 2342184610Salfred /* get current Transfer Descriptor */ 2343184610Salfred td = temp->td_next; 2344184610Salfred temp->td = td; 2345184610Salfred 2346184610Salfred /* prepare for next TD */ 2347184610Salfred temp->td_next = td->obj_next; 2348184610Salfred 2349184610Salfred /* fill out the Transfer Descriptor */ 2350184610Salfred td->func = temp->func; 2351184610Salfred td->pc = temp->pc; 2352184610Salfred td->offset = temp->offset; 2353184610Salfred td->remainder = temp->len; 2354184610Salfred td->error = 0; 2355257041Shselasky td->transaction_started = 0; 2356192552Sthompsa td->did_stall = temp->did_stall; 2357184610Salfred td->short_pkt = temp->short_pkt; 2358184610Salfred td->alt_next = temp->setup_alt_next; 2359257041Shselasky td->channel = temp->channel; 2360257041Shselasky td->dev_addr = temp->dev_addr; 2361257041Shselasky td->haddr = temp->haddr; 2362257041Shselasky td->hport = temp->hport; 2363257041Shselasky td->transfer_type = temp->transfer_type; 2364184610Salfred} 2365184610Salfred 2366184610Salfredstatic void 2367192984Sthompsamusbotg_setup_standard_chain(struct usb_xfer *xfer) 2368184610Salfred{ 2369184610Salfred struct musbotg_std_temp temp; 2370184610Salfred struct musbotg_softc *sc; 2371184610Salfred struct musbotg_td *td; 2372184610Salfred uint32_t x; 2373184610Salfred uint8_t ep_no; 2374257041Shselasky uint8_t xfer_type; 2375257041Shselasky enum usb_dev_speed speed; 2376257041Shselasky int tx; 2377257041Shselasky int dev_addr; 2378184610Salfred 2379184610Salfred DPRINTFN(8, "addr=%d endpt=%d sumlen=%d speed=%d\n", 2380193644Sthompsa xfer->address, UE_GET_ADDR(xfer->endpointno), 2381194228Sthompsa xfer->sumlen, usbd_get_speed(xfer->xroot->udev)); 2382184610Salfred 2383257041Shselasky sc = MUSBOTG_BUS2SC(xfer->xroot->bus); 2384257041Shselasky ep_no = (xfer->endpointno & UE_ADDR); 2385257041Shselasky 2386184610Salfred temp.max_frame_size = xfer->max_frame_size; 2387184610Salfred 2388184610Salfred td = xfer->td_start[0]; 2389184610Salfred xfer->td_transfer_first = td; 2390184610Salfred xfer->td_transfer_cache = td; 2391184610Salfred 2392184610Salfred /* setup temp */ 2393257041Shselasky dev_addr = xfer->address; 2394184610Salfred 2395257041Shselasky xfer_type = xfer->endpoint->edesc->bmAttributes & UE_XFERTYPE; 2396257041Shselasky 2397199673Sthompsa temp.pc = NULL; 2398184610Salfred temp.td = NULL; 2399184610Salfred temp.td_next = xfer->td_start[0]; 2400190183Sthompsa temp.offset = 0; 2401184610Salfred temp.setup_alt_next = xfer->flags_int.short_frames_ok; 2402192552Sthompsa temp.did_stall = !xfer->flags_int.control_stall; 2403257041Shselasky temp.channel = -1; 2404257041Shselasky temp.dev_addr = dev_addr; 2405257041Shselasky temp.haddr = xfer->xroot->udev->hs_hub_addr; 2406257041Shselasky temp.hport = xfer->xroot->udev->hs_port_no; 2407184610Salfred 2408257041Shselasky if (xfer->flags_int.usb_mode == USB_MODE_HOST) { 2409257041Shselasky speed = usbd_get_speed(xfer->xroot->udev); 2410184610Salfred 2411257041Shselasky switch (speed) { 2412257041Shselasky case USB_SPEED_LOW: 2413257041Shselasky temp.transfer_type = MUSB2_MASK_TI_SPEED_LO; 2414257041Shselasky break; 2415257041Shselasky case USB_SPEED_FULL: 2416257041Shselasky temp.transfer_type = MUSB2_MASK_TI_SPEED_FS; 2417257041Shselasky break; 2418257041Shselasky case USB_SPEED_HIGH: 2419257041Shselasky temp.transfer_type = MUSB2_MASK_TI_SPEED_HS; 2420257041Shselasky break; 2421257041Shselasky default: 2422257041Shselasky temp.transfer_type = 0; 2423257041Shselasky DPRINTFN(-1, "Invalid USB speed: %d\n", speed); 2424257041Shselasky break; 2425257041Shselasky } 2426257041Shselasky 2427257041Shselasky switch (xfer_type) { 2428257041Shselasky case UE_CONTROL: 2429257041Shselasky temp.transfer_type |= MUSB2_MASK_TI_PROTO_CTRL; 2430257041Shselasky break; 2431257041Shselasky case UE_ISOCHRONOUS: 2432257041Shselasky temp.transfer_type |= MUSB2_MASK_TI_PROTO_ISOC; 2433257041Shselasky break; 2434257041Shselasky case UE_BULK: 2435257041Shselasky temp.transfer_type |= MUSB2_MASK_TI_PROTO_BULK; 2436257041Shselasky break; 2437257041Shselasky case UE_INTERRUPT: 2438257041Shselasky temp.transfer_type |= MUSB2_MASK_TI_PROTO_INTR; 2439257041Shselasky break; 2440257041Shselasky default: 2441257041Shselasky DPRINTFN(-1, "Invalid USB transfer type: %d\n", 2442257041Shselasky xfer_type); 2443257041Shselasky break; 2444257041Shselasky } 2445257041Shselasky 2446257041Shselasky temp.transfer_type |= ep_no; 2447257041Shselasky td->toggle = xfer->endpoint->toggle_next; 2448257041Shselasky } 2449257041Shselasky 2450184610Salfred /* check if we should prepend a setup message */ 2451184610Salfred 2452184610Salfred if (xfer->flags_int.control_xfr) { 2453184610Salfred if (xfer->flags_int.control_hdr) { 2454184610Salfred 2455257041Shselasky if (xfer->flags_int.usb_mode == USB_MODE_DEVICE) 2456257041Shselasky temp.func = &musbotg_dev_ctrl_setup_rx; 2457257041Shselasky else 2458257041Shselasky temp.func = &musbotg_host_ctrl_setup_tx; 2459257041Shselasky 2460184610Salfred temp.len = xfer->frlengths[0]; 2461184610Salfred temp.pc = xfer->frbuffers + 0; 2462184610Salfred temp.short_pkt = temp.len ? 1 : 0; 2463184610Salfred 2464184610Salfred musbotg_setup_standard_chain_sub(&temp); 2465184610Salfred } 2466184610Salfred x = 1; 2467184610Salfred } else { 2468184610Salfred x = 0; 2469184610Salfred } 2470184610Salfred 2471257041Shselasky tx = 0; 2472257041Shselasky 2473184610Salfred if (x != xfer->nframes) { 2474257041Shselasky if (xfer->endpointno & UE_DIR_IN) 2475257041Shselasky tx = 1; 2476257041Shselasky 2477257041Shselasky if (xfer->flags_int.usb_mode == USB_MODE_HOST) { 2478257041Shselasky tx = !tx; 2479257041Shselasky 2480257041Shselasky if (tx) { 2481257041Shselasky if (xfer->flags_int.control_xfr) 2482257041Shselasky temp.func = &musbotg_host_ctrl_data_tx; 2483257041Shselasky else 2484257041Shselasky temp.func = &musbotg_host_data_tx; 2485257041Shselasky } else { 2486257041Shselasky if (xfer->flags_int.control_xfr) 2487257041Shselasky temp.func = &musbotg_host_ctrl_data_rx; 2488257041Shselasky else 2489257041Shselasky temp.func = &musbotg_host_data_rx; 2490257041Shselasky } 2491257041Shselasky 2492184610Salfred } else { 2493257041Shselasky if (tx) { 2494257041Shselasky if (xfer->flags_int.control_xfr) 2495257041Shselasky temp.func = &musbotg_dev_ctrl_data_tx; 2496257041Shselasky else 2497257041Shselasky temp.func = &musbotg_dev_data_tx; 2498257041Shselasky } else { 2499257041Shselasky if (xfer->flags_int.control_xfr) 2500257041Shselasky temp.func = &musbotg_dev_ctrl_data_rx; 2501257041Shselasky else 2502257041Shselasky temp.func = &musbotg_dev_data_rx; 2503257041Shselasky } 2504184610Salfred } 2505184610Salfred 2506184610Salfred /* setup "pc" pointer */ 2507184610Salfred temp.pc = xfer->frbuffers + x; 2508184610Salfred } 2509184610Salfred while (x != xfer->nframes) { 2510184610Salfred 2511184610Salfred /* DATA0 / DATA1 message */ 2512184610Salfred 2513184610Salfred temp.len = xfer->frlengths[x]; 2514184610Salfred 2515184610Salfred x++; 2516184610Salfred 2517184610Salfred if (x == xfer->nframes) { 2518190183Sthompsa if (xfer->flags_int.control_xfr) { 2519190183Sthompsa if (xfer->flags_int.control_act) { 2520190183Sthompsa temp.setup_alt_next = 0; 2521190183Sthompsa } 2522190183Sthompsa } else { 2523190183Sthompsa temp.setup_alt_next = 0; 2524190183Sthompsa } 2525184610Salfred } 2526184610Salfred if (temp.len == 0) { 2527184610Salfred 2528184610Salfred /* make sure that we send an USB packet */ 2529184610Salfred 2530184610Salfred temp.short_pkt = 0; 2531184610Salfred 2532184610Salfred } else { 2533184610Salfred 2534257041Shselasky if (xfer->flags_int.isochronous_xfr) { 2535257041Shselasky /* isochronous data transfer */ 2536257041Shselasky /* don't force short */ 2537257041Shselasky temp.short_pkt = 1; 2538257041Shselasky } else { 2539257041Shselasky /* regular data transfer */ 2540257041Shselasky temp.short_pkt = (xfer->flags.force_short_xfer ? 0 : 1); 2541257041Shselasky } 2542184610Salfred } 2543184610Salfred 2544184610Salfred musbotg_setup_standard_chain_sub(&temp); 2545184610Salfred 2546184610Salfred if (xfer->flags_int.isochronous_xfr) { 2547184610Salfred temp.offset += temp.len; 2548184610Salfred } else { 2549184610Salfred /* get next Page Cache pointer */ 2550184610Salfred temp.pc = xfer->frbuffers + x; 2551184610Salfred } 2552184610Salfred } 2553184610Salfred 2554190183Sthompsa /* check for control transfer */ 2555190183Sthompsa if (xfer->flags_int.control_xfr) { 2556184610Salfred 2557190183Sthompsa /* always setup a valid "pc" pointer for status and sync */ 2558190183Sthompsa temp.pc = xfer->frbuffers + 0; 2559184610Salfred temp.len = 0; 2560184610Salfred temp.short_pkt = 0; 2561190183Sthompsa temp.setup_alt_next = 0; 2562184610Salfred 2563190183Sthompsa /* check if we should append a status stage */ 2564190183Sthompsa if (!xfer->flags_int.control_act) { 2565190183Sthompsa /* 2566190183Sthompsa * Send a DATA1 message and invert the current 2567190183Sthompsa * endpoint direction. 2568190183Sthompsa */ 2569257041Shselasky if (sc->sc_mode == MUSB2_DEVICE_MODE) 2570257041Shselasky temp.func = &musbotg_dev_ctrl_status; 2571257041Shselasky else { 2572257041Shselasky if (xfer->endpointno & UE_DIR_IN) 2573257041Shselasky temp.func = musbotg_host_ctrl_status_tx; 2574257041Shselasky else 2575257041Shselasky temp.func = musbotg_host_ctrl_status_rx; 2576257041Shselasky } 2577190183Sthompsa musbotg_setup_standard_chain_sub(&temp); 2578190183Sthompsa } 2579184610Salfred } 2580184610Salfred /* must have at least one frame! */ 2581184610Salfred td = temp.td; 2582184610Salfred xfer->td_transfer_last = td; 2583184610Salfred} 2584184610Salfred 2585184610Salfredstatic void 2586184610Salfredmusbotg_timeout(void *arg) 2587184610Salfred{ 2588192984Sthompsa struct usb_xfer *xfer = arg; 2589184610Salfred 2590184610Salfred DPRINTFN(1, "xfer=%p\n", xfer); 2591184610Salfred 2592187173Sthompsa USB_BUS_LOCK_ASSERT(xfer->xroot->bus, MA_OWNED); 2593184610Salfred 2594184610Salfred /* transfer is transferred */ 2595184610Salfred musbotg_device_done(xfer, USB_ERR_TIMEOUT); 2596184610Salfred} 2597184610Salfred 2598184610Salfredstatic void 2599257041Shselaskymusbotg_ep_int_set(struct musbotg_softc *sc, int channel, int on) 2600184610Salfred{ 2601184610Salfred uint16_t temp; 2602184610Salfred 2603184610Salfred /* 2604184610Salfred * Only enable the endpoint interrupt when we are 2605184610Salfred * actually waiting for data, hence we are dealing 2606184610Salfred * with level triggered interrupts ! 2607184610Salfred */ 2608257041Shselasky DPRINTFN(1, "ep_no=%d, on=%d\n", channel, on); 2609257041Shselasky 2610257041Shselasky if (channel == -1) 2611257041Shselasky return; 2612257041Shselasky 2613257041Shselasky if (channel == 0) { 2614184610Salfred temp = MUSB2_READ_2(sc, MUSB2_REG_INTTXE); 2615184610Salfred if (on) 2616184610Salfred temp |= MUSB2_MASK_EPINT(0); 2617184610Salfred else 2618184610Salfred temp &= ~MUSB2_MASK_EPINT(0); 2619184610Salfred 2620184610Salfred MUSB2_WRITE_2(sc, MUSB2_REG_INTTXE, temp); 2621184610Salfred } else { 2622257041Shselasky temp = MUSB2_READ_2(sc, MUSB2_REG_INTRXE); 2623257041Shselasky if (on) 2624257041Shselasky temp |= MUSB2_MASK_EPINT(channel); 2625257041Shselasky else 2626257041Shselasky temp &= ~MUSB2_MASK_EPINT(channel); 2627257041Shselasky MUSB2_WRITE_2(sc, MUSB2_REG_INTRXE, temp); 2628184610Salfred 2629257041Shselasky temp = MUSB2_READ_2(sc, MUSB2_REG_INTTXE); 2630257041Shselasky if (on) 2631257041Shselasky temp |= MUSB2_MASK_EPINT(channel); 2632257041Shselasky else 2633257041Shselasky temp &= ~MUSB2_MASK_EPINT(channel); 2634257041Shselasky MUSB2_WRITE_2(sc, MUSB2_REG_INTTXE, temp); 2635184610Salfred } 2636257041Shselasky 2637257041Shselasky if (sc->sc_ep_int_set) 2638257041Shselasky sc->sc_ep_int_set(sc, channel, on); 2639184610Salfred} 2640184610Salfred 2641184610Salfredstatic void 2642192984Sthompsamusbotg_start_standard_chain(struct usb_xfer *xfer) 2643184610Salfred{ 2644184610Salfred DPRINTFN(8, "\n"); 2645184610Salfred 2646184610Salfred /* poll one time */ 2647184610Salfred if (musbotg_xfer_do_fifo(xfer)) { 2648184610Salfred 2649184610Salfred DPRINTFN(14, "enabled interrupts on endpoint\n"); 2650184610Salfred 2651184610Salfred /* put transfer on interrupt queue */ 2652194228Sthompsa usbd_transfer_enqueue(&xfer->xroot->bus->intr_q, xfer); 2653184610Salfred 2654184610Salfred /* start timeout, if any */ 2655184610Salfred if (xfer->timeout != 0) { 2656194228Sthompsa usbd_transfer_timeout_ms(xfer, 2657184610Salfred &musbotg_timeout, xfer->timeout); 2658184610Salfred } 2659184610Salfred } 2660184610Salfred} 2661184610Salfred 2662184610Salfredstatic void 2663190735Sthompsamusbotg_root_intr(struct musbotg_softc *sc) 2664184610Salfred{ 2665184610Salfred DPRINTFN(8, "\n"); 2666184610Salfred 2667184824Sthompsa USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED); 2668184610Salfred 2669184610Salfred /* set port bit */ 2670184610Salfred sc->sc_hub_idata[0] = 0x02; /* we only have one port */ 2671184610Salfred 2672190735Sthompsa uhub_root_intr(&sc->sc_bus, sc->sc_hub_idata, 2673190735Sthompsa sizeof(sc->sc_hub_idata)); 2674184610Salfred} 2675184610Salfred 2676193045Sthompsastatic usb_error_t 2677192984Sthompsamusbotg_standard_done_sub(struct usb_xfer *xfer) 2678184610Salfred{ 2679184610Salfred struct musbotg_td *td; 2680184610Salfred uint32_t len; 2681184610Salfred uint8_t error; 2682184610Salfred 2683184610Salfred DPRINTFN(8, "\n"); 2684184610Salfred 2685184610Salfred td = xfer->td_transfer_cache; 2686184610Salfred 2687184610Salfred do { 2688184610Salfred len = td->remainder; 2689184610Salfred 2690257041Shselasky xfer->endpoint->toggle_next = td->toggle; 2691257041Shselasky 2692184610Salfred if (xfer->aframes != xfer->nframes) { 2693184610Salfred /* 2694184610Salfred * Verify the length and subtract 2695184610Salfred * the remainder from "frlengths[]": 2696184610Salfred */ 2697184610Salfred if (len > xfer->frlengths[xfer->aframes]) { 2698184610Salfred td->error = 1; 2699184610Salfred } else { 2700184610Salfred xfer->frlengths[xfer->aframes] -= len; 2701184610Salfred } 2702184610Salfred } 2703184610Salfred /* Check for transfer error */ 2704184610Salfred if (td->error) { 2705184610Salfred /* the transfer is finished */ 2706184610Salfred error = 1; 2707184610Salfred td = NULL; 2708184610Salfred break; 2709184610Salfred } 2710184610Salfred /* Check for short transfer */ 2711184610Salfred if (len > 0) { 2712184610Salfred if (xfer->flags_int.short_frames_ok) { 2713184610Salfred /* follow alt next */ 2714184610Salfred if (td->alt_next) { 2715184610Salfred td = td->obj_next; 2716184610Salfred } else { 2717184610Salfred td = NULL; 2718184610Salfred } 2719184610Salfred } else { 2720184610Salfred /* the transfer is finished */ 2721184610Salfred td = NULL; 2722184610Salfred } 2723184610Salfred error = 0; 2724184610Salfred break; 2725184610Salfred } 2726184610Salfred td = td->obj_next; 2727184610Salfred 2728184610Salfred /* this USB frame is complete */ 2729184610Salfred error = 0; 2730184610Salfred break; 2731184610Salfred 2732184610Salfred } while (0); 2733184610Salfred 2734184610Salfred /* update transfer cache */ 2735184610Salfred 2736184610Salfred xfer->td_transfer_cache = td; 2737184610Salfred 2738184610Salfred return (error ? 2739184610Salfred USB_ERR_STALLED : USB_ERR_NORMAL_COMPLETION); 2740184610Salfred} 2741184610Salfred 2742184610Salfredstatic void 2743192984Sthompsamusbotg_standard_done(struct usb_xfer *xfer) 2744184610Salfred{ 2745193045Sthompsa usb_error_t err = 0; 2746184610Salfred 2747193644Sthompsa DPRINTFN(12, "xfer=%p endpoint=%p transfer done\n", 2748193644Sthompsa xfer, xfer->endpoint); 2749184610Salfred 2750184610Salfred /* reset scanner */ 2751184610Salfred 2752184610Salfred xfer->td_transfer_cache = xfer->td_transfer_first; 2753184610Salfred 2754184610Salfred if (xfer->flags_int.control_xfr) { 2755184610Salfred 2756184610Salfred if (xfer->flags_int.control_hdr) { 2757184610Salfred 2758184610Salfred err = musbotg_standard_done_sub(xfer); 2759184610Salfred } 2760184610Salfred xfer->aframes = 1; 2761184610Salfred 2762184610Salfred if (xfer->td_transfer_cache == NULL) { 2763184610Salfred goto done; 2764184610Salfred } 2765184610Salfred } 2766184610Salfred while (xfer->aframes != xfer->nframes) { 2767184610Salfred 2768184610Salfred err = musbotg_standard_done_sub(xfer); 2769184610Salfred xfer->aframes++; 2770184610Salfred 2771184610Salfred if (xfer->td_transfer_cache == NULL) { 2772184610Salfred goto done; 2773184610Salfred } 2774184610Salfred } 2775184610Salfred 2776184610Salfred if (xfer->flags_int.control_xfr && 2777184610Salfred !xfer->flags_int.control_act) { 2778184610Salfred 2779184610Salfred err = musbotg_standard_done_sub(xfer); 2780184610Salfred } 2781184610Salfreddone: 2782184610Salfred musbotg_device_done(xfer, err); 2783184610Salfred} 2784184610Salfred 2785184610Salfred/*------------------------------------------------------------------------* 2786184610Salfred * musbotg_device_done 2787184610Salfred * 2788184610Salfred * NOTE: this function can be called more than one time on the 2789184610Salfred * same USB transfer! 2790184610Salfred *------------------------------------------------------------------------*/ 2791184610Salfredstatic void 2792193045Sthompsamusbotg_device_done(struct usb_xfer *xfer, usb_error_t error) 2793184610Salfred{ 2794257041Shselasky struct musbotg_td *td; 2795257041Shselasky struct musbotg_softc *sc; 2796257041Shselasky 2797187173Sthompsa USB_BUS_LOCK_ASSERT(xfer->xroot->bus, MA_OWNED); 2798184610Salfred 2799257041Shselasky DPRINTFN(1, "xfer=%p, endpoint=%p, error=%d\n", 2800193644Sthompsa xfer, xfer->endpoint, error); 2801184610Salfred 2802257041Shselasky DPRINTFN(14, "disabled interrupts on endpoint\n"); 2803184610Salfred 2804257041Shselasky sc = MUSBOTG_BUS2SC(xfer->xroot->bus); 2805257041Shselasky td = xfer->td_transfer_cache; 2806184610Salfred 2807257041Shselasky if (td && (td->channel != -1)) 2808257041Shselasky musbotg_channel_free(sc, td); 2809257041Shselasky 2810184610Salfred /* dequeue transfer and start next transfer */ 2811194228Sthompsa usbd_transfer_done(xfer, error); 2812184610Salfred} 2813184610Salfred 2814184610Salfredstatic void 2815192984Sthompsamusbotg_set_stall(struct usb_device *udev, struct usb_xfer *xfer, 2816195121Sthompsa struct usb_endpoint *ep, uint8_t *did_stall) 2817184610Salfred{ 2818184610Salfred struct musbotg_softc *sc; 2819184610Salfred uint8_t ep_no; 2820184610Salfred 2821184824Sthompsa USB_BUS_LOCK_ASSERT(udev->bus, MA_OWNED); 2822184610Salfred 2823193644Sthompsa DPRINTFN(4, "endpoint=%p\n", ep); 2824184610Salfred 2825184610Salfred if (xfer) { 2826184610Salfred /* cancel any ongoing transfers */ 2827184610Salfred musbotg_device_done(xfer, USB_ERR_STALLED); 2828184610Salfred } 2829184610Salfred /* set FORCESTALL */ 2830184610Salfred sc = MUSBOTG_BUS2SC(udev->bus); 2831184610Salfred 2832193644Sthompsa ep_no = (ep->edesc->bEndpointAddress & UE_ADDR); 2833184610Salfred 2834184610Salfred /* select endpoint */ 2835184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_EPINDEX, ep_no); 2836184610Salfred 2837193644Sthompsa if (ep->edesc->bEndpointAddress & UE_DIR_IN) { 2838184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 2839184610Salfred MUSB2_MASK_CSRL_TXSENDSTALL); 2840184610Salfred } else { 2841184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_RXCSRL, 2842184610Salfred MUSB2_MASK_CSRL_RXSENDSTALL); 2843184610Salfred } 2844184610Salfred} 2845184610Salfred 2846184610Salfredstatic void 2847184610Salfredmusbotg_clear_stall_sub(struct musbotg_softc *sc, uint16_t wMaxPacket, 2848184610Salfred uint8_t ep_no, uint8_t ep_type, uint8_t ep_dir) 2849184610Salfred{ 2850184610Salfred uint16_t mps; 2851184610Salfred uint16_t temp; 2852184610Salfred uint8_t csr; 2853184610Salfred 2854184610Salfred if (ep_type == UE_CONTROL) { 2855184610Salfred /* clearing stall is not needed */ 2856184610Salfred return; 2857184610Salfred } 2858184610Salfred /* select endpoint */ 2859184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_EPINDEX, ep_no); 2860184610Salfred 2861184610Salfred /* compute max frame size */ 2862184610Salfred mps = wMaxPacket & 0x7FF; 2863184610Salfred switch ((wMaxPacket >> 11) & 3) { 2864184610Salfred case 1: 2865184610Salfred mps *= 2; 2866184610Salfred break; 2867184610Salfred case 2: 2868184610Salfred mps *= 3; 2869184610Salfred break; 2870184610Salfred default: 2871184610Salfred break; 2872184610Salfred } 2873184610Salfred 2874184610Salfred if (ep_dir == UE_DIR_IN) { 2875184610Salfred 2876184610Salfred temp = 0; 2877184610Salfred 2878184610Salfred /* Configure endpoint */ 2879184610Salfred switch (ep_type) { 2880184610Salfred case UE_INTERRUPT: 2881199676Sthompsa MUSB2_WRITE_2(sc, MUSB2_REG_TXMAXP, wMaxPacket); 2882184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRH, 2883184610Salfred MUSB2_MASK_CSRH_TXMODE | temp); 2884184610Salfred break; 2885184610Salfred case UE_ISOCHRONOUS: 2886199676Sthompsa MUSB2_WRITE_2(sc, MUSB2_REG_TXMAXP, wMaxPacket); 2887184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRH, 2888184610Salfred MUSB2_MASK_CSRH_TXMODE | 2889184610Salfred MUSB2_MASK_CSRH_TXISO | temp); 2890184610Salfred break; 2891184610Salfred case UE_BULK: 2892199676Sthompsa MUSB2_WRITE_2(sc, MUSB2_REG_TXMAXP, wMaxPacket); 2893184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRH, 2894184610Salfred MUSB2_MASK_CSRH_TXMODE | temp); 2895184610Salfred break; 2896184610Salfred default: 2897184610Salfred break; 2898184610Salfred } 2899184610Salfred 2900184610Salfred /* Need to flush twice in case of double bufring */ 2901184610Salfred csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL); 2902184610Salfred if (csr & MUSB2_MASK_CSRL_TXFIFONEMPTY) { 2903184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 2904184610Salfred MUSB2_MASK_CSRL_TXFFLUSH); 2905184610Salfred csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL); 2906184610Salfred if (csr & MUSB2_MASK_CSRL_TXFIFONEMPTY) { 2907184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 2908184610Salfred MUSB2_MASK_CSRL_TXFFLUSH); 2909184610Salfred csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL); 2910184610Salfred } 2911184610Salfred } 2912184610Salfred /* reset data toggle */ 2913184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 2914184610Salfred MUSB2_MASK_CSRL_TXDT_CLR); 2915184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 0); 2916184610Salfred csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL); 2917184610Salfred 2918184610Salfred /* set double/single buffering */ 2919184610Salfred temp = MUSB2_READ_2(sc, MUSB2_REG_TXDBDIS); 2920184610Salfred if (mps <= (sc->sc_hw_ep_profile[ep_no]. 2921184610Salfred max_in_frame_size / 2)) { 2922184610Salfred /* double buffer */ 2923184610Salfred temp &= ~(1 << ep_no); 2924184610Salfred } else { 2925184610Salfred /* single buffer */ 2926184610Salfred temp |= (1 << ep_no); 2927184610Salfred } 2928184610Salfred MUSB2_WRITE_2(sc, MUSB2_REG_TXDBDIS, temp); 2929184610Salfred 2930184610Salfred /* clear sent stall */ 2931184610Salfred if (csr & MUSB2_MASK_CSRL_TXSENTSTALL) { 2932184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_TXCSRL, 0); 2933184610Salfred csr = MUSB2_READ_1(sc, MUSB2_REG_TXCSRL); 2934184610Salfred } 2935184610Salfred } else { 2936184610Salfred 2937184610Salfred temp = 0; 2938184610Salfred 2939184610Salfred /* Configure endpoint */ 2940184610Salfred switch (ep_type) { 2941184610Salfred case UE_INTERRUPT: 2942199676Sthompsa MUSB2_WRITE_2(sc, MUSB2_REG_RXMAXP, wMaxPacket); 2943184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_RXCSRH, 2944184610Salfred MUSB2_MASK_CSRH_RXNYET | temp); 2945184610Salfred break; 2946184610Salfred case UE_ISOCHRONOUS: 2947199676Sthompsa MUSB2_WRITE_2(sc, MUSB2_REG_RXMAXP, wMaxPacket); 2948184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_RXCSRH, 2949184610Salfred MUSB2_MASK_CSRH_RXNYET | 2950184610Salfred MUSB2_MASK_CSRH_RXISO | temp); 2951184610Salfred break; 2952184610Salfred case UE_BULK: 2953199676Sthompsa MUSB2_WRITE_2(sc, MUSB2_REG_RXMAXP, wMaxPacket); 2954184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_RXCSRH, temp); 2955184610Salfred break; 2956184610Salfred default: 2957184610Salfred break; 2958184610Salfred } 2959184610Salfred 2960184610Salfred /* Need to flush twice in case of double bufring */ 2961184610Salfred csr = MUSB2_READ_1(sc, MUSB2_REG_RXCSRL); 2962184610Salfred if (csr & MUSB2_MASK_CSRL_RXPKTRDY) { 2963184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_RXCSRL, 2964184610Salfred MUSB2_MASK_CSRL_RXFFLUSH); 2965184610Salfred csr = MUSB2_READ_1(sc, MUSB2_REG_RXCSRL); 2966184610Salfred if (csr & MUSB2_MASK_CSRL_RXPKTRDY) { 2967184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_RXCSRL, 2968184610Salfred MUSB2_MASK_CSRL_RXFFLUSH); 2969184610Salfred csr = MUSB2_READ_1(sc, MUSB2_REG_RXCSRL); 2970184610Salfred } 2971184610Salfred } 2972184610Salfred /* reset data toggle */ 2973184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_RXCSRL, 2974184610Salfred MUSB2_MASK_CSRL_RXDT_CLR); 2975184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_RXCSRL, 0); 2976184610Salfred csr = MUSB2_READ_1(sc, MUSB2_REG_RXCSRL); 2977184610Salfred 2978184610Salfred /* set double/single buffering */ 2979184610Salfred temp = MUSB2_READ_2(sc, MUSB2_REG_RXDBDIS); 2980184610Salfred if (mps <= (sc->sc_hw_ep_profile[ep_no]. 2981184610Salfred max_out_frame_size / 2)) { 2982184610Salfred /* double buffer */ 2983184610Salfred temp &= ~(1 << ep_no); 2984184610Salfred } else { 2985184610Salfred /* single buffer */ 2986184610Salfred temp |= (1 << ep_no); 2987184610Salfred } 2988184610Salfred MUSB2_WRITE_2(sc, MUSB2_REG_RXDBDIS, temp); 2989184610Salfred 2990184610Salfred /* clear sent stall */ 2991184610Salfred if (csr & MUSB2_MASK_CSRL_RXSENTSTALL) { 2992184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_RXCSRL, 0); 2993184610Salfred } 2994184610Salfred } 2995184610Salfred} 2996184610Salfred 2997184610Salfredstatic void 2998193644Sthompsamusbotg_clear_stall(struct usb_device *udev, struct usb_endpoint *ep) 2999184610Salfred{ 3000184610Salfred struct musbotg_softc *sc; 3001192984Sthompsa struct usb_endpoint_descriptor *ed; 3002184610Salfred 3003193644Sthompsa DPRINTFN(4, "endpoint=%p\n", ep); 3004184610Salfred 3005184824Sthompsa USB_BUS_LOCK_ASSERT(udev->bus, MA_OWNED); 3006184610Salfred 3007184610Salfred /* check mode */ 3008192499Sthompsa if (udev->flags.usb_mode != USB_MODE_DEVICE) { 3009184610Salfred /* not supported */ 3010184610Salfred return; 3011184610Salfred } 3012184610Salfred /* get softc */ 3013184610Salfred sc = MUSBOTG_BUS2SC(udev->bus); 3014184610Salfred 3015184610Salfred /* get endpoint descriptor */ 3016193644Sthompsa ed = ep->edesc; 3017184610Salfred 3018184610Salfred /* reset endpoint */ 3019184610Salfred musbotg_clear_stall_sub(sc, 3020184610Salfred UGETW(ed->wMaxPacketSize), 3021184610Salfred (ed->bEndpointAddress & UE_ADDR), 3022184610Salfred (ed->bmAttributes & UE_XFERTYPE), 3023184610Salfred (ed->bEndpointAddress & (UE_DIR_IN | UE_DIR_OUT))); 3024184610Salfred} 3025184610Salfred 3026193045Sthompsausb_error_t 3027184610Salfredmusbotg_init(struct musbotg_softc *sc) 3028184610Salfred{ 3029192984Sthompsa struct usb_hw_ep_profile *pf; 3030199676Sthompsa uint16_t offset; 3031184610Salfred uint8_t nrx; 3032184610Salfred uint8_t ntx; 3033184610Salfred uint8_t temp; 3034184610Salfred uint8_t fsize; 3035184610Salfred uint8_t frx; 3036184610Salfred uint8_t ftx; 3037199676Sthompsa uint8_t dynfifo; 3038184610Salfred 3039184610Salfred DPRINTFN(1, "start\n"); 3040184610Salfred 3041184610Salfred /* set up the bus structure */ 3042184610Salfred sc->sc_bus.usbrev = USB_REV_2_0; 3043184610Salfred sc->sc_bus.methods = &musbotg_bus_methods; 3044184610Salfred 3045184824Sthompsa USB_BUS_LOCK(&sc->sc_bus); 3046184610Salfred 3047184610Salfred /* turn on clocks */ 3048184610Salfred 3049184610Salfred if (sc->sc_clocks_on) { 3050184610Salfred (sc->sc_clocks_on) (sc->sc_clocks_arg); 3051184610Salfred } 3052257041Shselasky 3053184610Salfred /* wait a little for things to stabilise */ 3054194228Sthompsa usb_pause_mtx(&sc->sc_bus.bus_mtx, hz / 1000); 3055184610Salfred 3056184610Salfred /* disable all interrupts */ 3057184610Salfred 3058257041Shselasky temp = MUSB2_READ_1(sc, MUSB2_REG_DEVCTL); 3059257041Shselasky DPRINTF("pre-DEVCTL=0x%02x\n", temp); 3060257041Shselasky 3061184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_INTUSBE, 0); 3062184610Salfred MUSB2_WRITE_2(sc, MUSB2_REG_INTTXE, 0); 3063184610Salfred MUSB2_WRITE_2(sc, MUSB2_REG_INTRXE, 0); 3064184610Salfred 3065184610Salfred /* disable pullup */ 3066184610Salfred 3067184610Salfred musbotg_pull_common(sc, 0); 3068184610Salfred 3069184610Salfred /* wait a little bit (10ms) */ 3070194228Sthompsa usb_pause_mtx(&sc->sc_bus.bus_mtx, hz / 100); 3071184610Salfred 3072257041Shselasky 3073184610Salfred /* disable double packet buffering */ 3074184610Salfred MUSB2_WRITE_2(sc, MUSB2_REG_RXDBDIS, 0xFFFF); 3075184610Salfred MUSB2_WRITE_2(sc, MUSB2_REG_TXDBDIS, 0xFFFF); 3076184610Salfred 3077184610Salfred /* enable HighSpeed and ISO Update flags */ 3078184610Salfred 3079184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_POWER, 3080184610Salfred MUSB2_MASK_HSENAB | MUSB2_MASK_ISOUPD); 3081184610Salfred 3082257041Shselasky if (sc->sc_mode == MUSB2_DEVICE_MODE) { 3083257041Shselasky /* clear Session bit, if set */ 3084257041Shselasky temp = MUSB2_READ_1(sc, MUSB2_REG_DEVCTL); 3085257041Shselasky temp &= ~MUSB2_MASK_SESS; 3086257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_DEVCTL, temp); 3087257041Shselasky } else { 3088257041Shselasky /* Enter session for Host mode */ 3089257041Shselasky temp = MUSB2_READ_1(sc, MUSB2_REG_DEVCTL); 3090257041Shselasky temp |= MUSB2_MASK_SESS; 3091257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_DEVCTL, temp); 3092257041Shselasky } 3093184610Salfred 3094257041Shselasky /* wait a little for things to stabilise */ 3095257041Shselasky usb_pause_mtx(&sc->sc_bus.bus_mtx, hz / 10); 3096184610Salfred 3097184610Salfred DPRINTF("DEVCTL=0x%02x\n", temp); 3098184610Salfred 3099184610Salfred /* disable testmode */ 3100184610Salfred 3101184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_TESTMODE, 0); 3102184610Salfred 3103184610Salfred /* set default value */ 3104184610Salfred 3105184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_MISC, 0); 3106184610Salfred 3107184610Salfred /* select endpoint index 0 */ 3108184610Salfred 3109184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_EPINDEX, 0); 3110184610Salfred 3111184610Salfred /* read out number of endpoints */ 3112184610Salfred 3113184610Salfred nrx = 3114184610Salfred (MUSB2_READ_1(sc, MUSB2_REG_EPINFO) / 16); 3115184610Salfred 3116184610Salfred ntx = 3117184610Salfred (MUSB2_READ_1(sc, MUSB2_REG_EPINFO) % 16); 3118184610Salfred 3119184610Salfred /* these numbers exclude the control endpoint */ 3120184610Salfred 3121184610Salfred DPRINTFN(2, "RX/TX endpoints: %u/%u\n", nrx, ntx); 3122184610Salfred 3123184610Salfred sc->sc_ep_max = (nrx > ntx) ? nrx : ntx; 3124184610Salfred if (sc->sc_ep_max == 0) { 3125184610Salfred DPRINTFN(2, "ERROR: Looks like the clocks are off!\n"); 3126184610Salfred } 3127184610Salfred /* read out configuration data */ 3128184610Salfred 3129184610Salfred sc->sc_conf_data = MUSB2_READ_1(sc, MUSB2_REG_CONFDATA); 3130184610Salfred 3131184610Salfred DPRINTFN(2, "Config Data: 0x%02x\n", 3132184610Salfred sc->sc_conf_data); 3133184610Salfred 3134199676Sthompsa dynfifo = (sc->sc_conf_data & MUSB2_MASK_CD_DYNFIFOSZ) ? 1 : 0; 3135199676Sthompsa 3136199676Sthompsa if (dynfifo) { 3137199816Sthompsa device_printf(sc->sc_bus.bdev, "Dynamic FIFO sizing detected, " 3138199816Sthompsa "assuming 16Kbytes of FIFO RAM\n"); 3139199676Sthompsa } 3140199676Sthompsa 3141184610Salfred DPRINTFN(2, "HW version: 0x%04x\n", 3142184610Salfred MUSB2_READ_1(sc, MUSB2_REG_HWVERS)); 3143184610Salfred 3144184610Salfred /* initialise endpoint profiles */ 3145184610Salfred 3146199676Sthompsa offset = 0; 3147199676Sthompsa 3148184610Salfred for (temp = 1; temp <= sc->sc_ep_max; temp++) { 3149184610Salfred pf = sc->sc_hw_ep_profile + temp; 3150184610Salfred 3151184610Salfred /* select endpoint */ 3152184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_EPINDEX, temp); 3153184610Salfred 3154184610Salfred fsize = MUSB2_READ_1(sc, MUSB2_REG_FSIZE); 3155201758Smbr frx = (fsize & MUSB2_MASK_RX_FSIZE) / 16; 3156184610Salfred ftx = (fsize & MUSB2_MASK_TX_FSIZE); 3157184610Salfred 3158199676Sthompsa DPRINTF("Endpoint %u FIFO size: IN=%u, OUT=%u, DYN=%d\n", 3159199676Sthompsa temp, ftx, frx, dynfifo); 3160184610Salfred 3161199676Sthompsa if (dynfifo) { 3162199676Sthompsa if (frx && (temp <= nrx)) { 3163257041Shselasky if (temp == 1) { 3164257041Shselasky frx = 12; /* 4K */ 3165257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_RXFIFOSZ, 3166257041Shselasky MUSB2_VAL_FIFOSZ_4096 | 3167257041Shselasky MUSB2_MASK_FIFODB); 3168257041Shselasky } else if (temp < 8) { 3169199676Sthompsa frx = 10; /* 1K */ 3170199676Sthompsa MUSB2_WRITE_1(sc, MUSB2_REG_RXFIFOSZ, 3171199676Sthompsa MUSB2_VAL_FIFOSZ_512 | 3172199676Sthompsa MUSB2_MASK_FIFODB); 3173199676Sthompsa } else { 3174199676Sthompsa frx = 7; /* 128 bytes */ 3175199676Sthompsa MUSB2_WRITE_1(sc, MUSB2_REG_RXFIFOSZ, 3176199676Sthompsa MUSB2_VAL_FIFOSZ_128); 3177199676Sthompsa } 3178199676Sthompsa 3179199676Sthompsa MUSB2_WRITE_2(sc, MUSB2_REG_RXFIFOADD, 3180199676Sthompsa offset >> 3); 3181199676Sthompsa 3182199676Sthompsa offset += (1 << frx); 3183199676Sthompsa } 3184199676Sthompsa if (ftx && (temp <= ntx)) { 3185257041Shselasky if (temp == 1) { 3186257041Shselasky ftx = 12; /* 4K */ 3187257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_TXFIFOSZ, 3188257041Shselasky MUSB2_VAL_FIFOSZ_4096 | 3189257041Shselasky MUSB2_MASK_FIFODB); 3190257041Shselasky } else if (temp < 8) { 3191199676Sthompsa ftx = 10; /* 1K */ 3192199676Sthompsa MUSB2_WRITE_1(sc, MUSB2_REG_TXFIFOSZ, 3193199676Sthompsa MUSB2_VAL_FIFOSZ_512 | 3194199676Sthompsa MUSB2_MASK_FIFODB); 3195199676Sthompsa } else { 3196199676Sthompsa ftx = 7; /* 128 bytes */ 3197199676Sthompsa MUSB2_WRITE_1(sc, MUSB2_REG_TXFIFOSZ, 3198199676Sthompsa MUSB2_VAL_FIFOSZ_128); 3199199676Sthompsa } 3200199676Sthompsa 3201199676Sthompsa MUSB2_WRITE_2(sc, MUSB2_REG_TXFIFOADD, 3202199676Sthompsa offset >> 3); 3203199676Sthompsa 3204199676Sthompsa offset += (1 << ftx); 3205199676Sthompsa } 3206199676Sthompsa } 3207199676Sthompsa 3208184610Salfred if (frx && ftx && (temp <= nrx) && (temp <= ntx)) { 3209184610Salfred pf->max_in_frame_size = 1 << ftx; 3210184610Salfred pf->max_out_frame_size = 1 << frx; 3211184610Salfred pf->is_simplex = 0; /* duplex */ 3212184610Salfred pf->support_multi_buffer = 1; 3213184610Salfred pf->support_bulk = 1; 3214184610Salfred pf->support_interrupt = 1; 3215184610Salfred pf->support_isochronous = 1; 3216184610Salfred pf->support_in = 1; 3217184610Salfred pf->support_out = 1; 3218184610Salfred } else if (frx && (temp <= nrx)) { 3219184610Salfred pf->max_out_frame_size = 1 << frx; 3220184610Salfred pf->is_simplex = 1; /* simplex */ 3221184610Salfred pf->support_multi_buffer = 1; 3222184610Salfred pf->support_bulk = 1; 3223184610Salfred pf->support_interrupt = 1; 3224184610Salfred pf->support_isochronous = 1; 3225184610Salfred pf->support_out = 1; 3226184610Salfred } else if (ftx && (temp <= ntx)) { 3227184610Salfred pf->max_in_frame_size = 1 << ftx; 3228184610Salfred pf->is_simplex = 1; /* simplex */ 3229184610Salfred pf->support_multi_buffer = 1; 3230184610Salfred pf->support_bulk = 1; 3231184610Salfred pf->support_interrupt = 1; 3232184610Salfred pf->support_isochronous = 1; 3233184610Salfred pf->support_in = 1; 3234184610Salfred } 3235184610Salfred } 3236184610Salfred 3237199676Sthompsa DPRINTFN(2, "Dynamic FIFO size = %d bytes\n", offset); 3238199676Sthompsa 3239184610Salfred /* turn on default interrupts */ 3240184610Salfred 3241257041Shselasky if (sc->sc_mode == MUSB2_HOST_MODE) 3242257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_INTUSBE, 0xff); 3243257041Shselasky else 3244257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_INTUSBE, 3245257041Shselasky MUSB2_MASK_IRESET); 3246184610Salfred 3247184610Salfred musbotg_clocks_off(sc); 3248184610Salfred 3249184824Sthompsa USB_BUS_UNLOCK(&sc->sc_bus); 3250184610Salfred 3251184610Salfred /* catch any lost interrupts */ 3252184610Salfred 3253184610Salfred musbotg_do_poll(&sc->sc_bus); 3254184610Salfred 3255184610Salfred return (0); /* success */ 3256184610Salfred} 3257184610Salfred 3258184610Salfredvoid 3259184610Salfredmusbotg_uninit(struct musbotg_softc *sc) 3260184610Salfred{ 3261184824Sthompsa USB_BUS_LOCK(&sc->sc_bus); 3262184610Salfred 3263184610Salfred /* disable all interrupts */ 3264184610Salfred MUSB2_WRITE_1(sc, MUSB2_REG_INTUSBE, 0); 3265184610Salfred MUSB2_WRITE_2(sc, MUSB2_REG_INTTXE, 0); 3266184610Salfred MUSB2_WRITE_2(sc, MUSB2_REG_INTRXE, 0); 3267184610Salfred 3268184610Salfred sc->sc_flags.port_powered = 0; 3269184610Salfred sc->sc_flags.status_vbus = 0; 3270184610Salfred sc->sc_flags.status_bus_reset = 0; 3271184610Salfred sc->sc_flags.status_suspend = 0; 3272184610Salfred sc->sc_flags.change_suspend = 0; 3273184610Salfred sc->sc_flags.change_connect = 1; 3274184610Salfred 3275184610Salfred musbotg_pull_down(sc); 3276184610Salfred musbotg_clocks_off(sc); 3277184824Sthompsa USB_BUS_UNLOCK(&sc->sc_bus); 3278184610Salfred} 3279184610Salfred 3280229096Shselaskystatic void 3281184610Salfredmusbotg_suspend(struct musbotg_softc *sc) 3282184610Salfred{ 3283229096Shselasky /* TODO */ 3284184610Salfred} 3285184610Salfred 3286229096Shselaskystatic void 3287184610Salfredmusbotg_resume(struct musbotg_softc *sc) 3288184610Salfred{ 3289229096Shselasky /* TODO */ 3290184610Salfred} 3291184610Salfred 3292184610Salfredstatic void 3293192984Sthompsamusbotg_do_poll(struct usb_bus *bus) 3294184610Salfred{ 3295184610Salfred struct musbotg_softc *sc = MUSBOTG_BUS2SC(bus); 3296184610Salfred 3297184824Sthompsa USB_BUS_LOCK(&sc->sc_bus); 3298184610Salfred musbotg_interrupt_poll(sc); 3299184824Sthompsa USB_BUS_UNLOCK(&sc->sc_bus); 3300184610Salfred} 3301184610Salfred 3302184610Salfred/*------------------------------------------------------------------------* 3303184610Salfred * musbotg bulk support 3304184610Salfred *------------------------------------------------------------------------*/ 3305184610Salfredstatic void 3306192984Sthompsamusbotg_device_bulk_open(struct usb_xfer *xfer) 3307184610Salfred{ 3308184610Salfred return; 3309184610Salfred} 3310184610Salfred 3311184610Salfredstatic void 3312192984Sthompsamusbotg_device_bulk_close(struct usb_xfer *xfer) 3313184610Salfred{ 3314184610Salfred musbotg_device_done(xfer, USB_ERR_CANCELLED); 3315184610Salfred} 3316184610Salfred 3317184610Salfredstatic void 3318192984Sthompsamusbotg_device_bulk_enter(struct usb_xfer *xfer) 3319184610Salfred{ 3320184610Salfred return; 3321184610Salfred} 3322184610Salfred 3323184610Salfredstatic void 3324192984Sthompsamusbotg_device_bulk_start(struct usb_xfer *xfer) 3325184610Salfred{ 3326184610Salfred /* setup TDs */ 3327184610Salfred musbotg_setup_standard_chain(xfer); 3328184610Salfred musbotg_start_standard_chain(xfer); 3329184610Salfred} 3330184610Salfred 3331192984Sthompsastruct usb_pipe_methods musbotg_device_bulk_methods = 3332184610Salfred{ 3333184610Salfred .open = musbotg_device_bulk_open, 3334184610Salfred .close = musbotg_device_bulk_close, 3335184610Salfred .enter = musbotg_device_bulk_enter, 3336184610Salfred .start = musbotg_device_bulk_start, 3337184610Salfred}; 3338184610Salfred 3339184610Salfred/*------------------------------------------------------------------------* 3340184610Salfred * musbotg control support 3341184610Salfred *------------------------------------------------------------------------*/ 3342184610Salfredstatic void 3343192984Sthompsamusbotg_device_ctrl_open(struct usb_xfer *xfer) 3344184610Salfred{ 3345184610Salfred return; 3346184610Salfred} 3347184610Salfred 3348184610Salfredstatic void 3349192984Sthompsamusbotg_device_ctrl_close(struct usb_xfer *xfer) 3350184610Salfred{ 3351184610Salfred musbotg_device_done(xfer, USB_ERR_CANCELLED); 3352184610Salfred} 3353184610Salfred 3354184610Salfredstatic void 3355192984Sthompsamusbotg_device_ctrl_enter(struct usb_xfer *xfer) 3356184610Salfred{ 3357184610Salfred return; 3358184610Salfred} 3359184610Salfred 3360184610Salfredstatic void 3361192984Sthompsamusbotg_device_ctrl_start(struct usb_xfer *xfer) 3362184610Salfred{ 3363184610Salfred /* setup TDs */ 3364184610Salfred musbotg_setup_standard_chain(xfer); 3365184610Salfred musbotg_start_standard_chain(xfer); 3366184610Salfred} 3367184610Salfred 3368192984Sthompsastruct usb_pipe_methods musbotg_device_ctrl_methods = 3369184610Salfred{ 3370184610Salfred .open = musbotg_device_ctrl_open, 3371184610Salfred .close = musbotg_device_ctrl_close, 3372184610Salfred .enter = musbotg_device_ctrl_enter, 3373184610Salfred .start = musbotg_device_ctrl_start, 3374184610Salfred}; 3375184610Salfred 3376184610Salfred/*------------------------------------------------------------------------* 3377184610Salfred * musbotg interrupt support 3378184610Salfred *------------------------------------------------------------------------*/ 3379184610Salfredstatic void 3380192984Sthompsamusbotg_device_intr_open(struct usb_xfer *xfer) 3381184610Salfred{ 3382184610Salfred return; 3383184610Salfred} 3384184610Salfred 3385184610Salfredstatic void 3386192984Sthompsamusbotg_device_intr_close(struct usb_xfer *xfer) 3387184610Salfred{ 3388184610Salfred musbotg_device_done(xfer, USB_ERR_CANCELLED); 3389184610Salfred} 3390184610Salfred 3391184610Salfredstatic void 3392192984Sthompsamusbotg_device_intr_enter(struct usb_xfer *xfer) 3393184610Salfred{ 3394184610Salfred return; 3395184610Salfred} 3396184610Salfred 3397184610Salfredstatic void 3398192984Sthompsamusbotg_device_intr_start(struct usb_xfer *xfer) 3399184610Salfred{ 3400184610Salfred /* setup TDs */ 3401184610Salfred musbotg_setup_standard_chain(xfer); 3402184610Salfred musbotg_start_standard_chain(xfer); 3403184610Salfred} 3404184610Salfred 3405192984Sthompsastruct usb_pipe_methods musbotg_device_intr_methods = 3406184610Salfred{ 3407184610Salfred .open = musbotg_device_intr_open, 3408184610Salfred .close = musbotg_device_intr_close, 3409184610Salfred .enter = musbotg_device_intr_enter, 3410184610Salfred .start = musbotg_device_intr_start, 3411184610Salfred}; 3412184610Salfred 3413184610Salfred/*------------------------------------------------------------------------* 3414184610Salfred * musbotg full speed isochronous support 3415184610Salfred *------------------------------------------------------------------------*/ 3416184610Salfredstatic void 3417192984Sthompsamusbotg_device_isoc_open(struct usb_xfer *xfer) 3418184610Salfred{ 3419184610Salfred return; 3420184610Salfred} 3421184610Salfred 3422184610Salfredstatic void 3423192984Sthompsamusbotg_device_isoc_close(struct usb_xfer *xfer) 3424184610Salfred{ 3425184610Salfred musbotg_device_done(xfer, USB_ERR_CANCELLED); 3426184610Salfred} 3427184610Salfred 3428184610Salfredstatic void 3429192984Sthompsamusbotg_device_isoc_enter(struct usb_xfer *xfer) 3430184610Salfred{ 3431187173Sthompsa struct musbotg_softc *sc = MUSBOTG_BUS2SC(xfer->xroot->bus); 3432184610Salfred uint32_t temp; 3433184610Salfred uint32_t nframes; 3434184610Salfred uint32_t fs_frames; 3435184610Salfred 3436184610Salfred DPRINTFN(5, "xfer=%p next=%d nframes=%d\n", 3437193644Sthompsa xfer, xfer->endpoint->isoc_next, xfer->nframes); 3438184610Salfred 3439184610Salfred /* get the current frame index */ 3440184610Salfred 3441184610Salfred nframes = MUSB2_READ_2(sc, MUSB2_REG_FRAME); 3442184610Salfred 3443184610Salfred /* 3444184610Salfred * check if the frame index is within the window where the frames 3445184610Salfred * will be inserted 3446184610Salfred */ 3447193644Sthompsa temp = (nframes - xfer->endpoint->isoc_next) & MUSB2_MASK_FRAME; 3448184610Salfred 3449194228Sthompsa if (usbd_get_speed(xfer->xroot->udev) == USB_SPEED_HIGH) { 3450184610Salfred fs_frames = (xfer->nframes + 7) / 8; 3451184610Salfred } else { 3452184610Salfred fs_frames = xfer->nframes; 3453184610Salfred } 3454184610Salfred 3455193644Sthompsa if ((xfer->endpoint->is_synced == 0) || 3456184610Salfred (temp < fs_frames)) { 3457184610Salfred /* 3458184610Salfred * If there is data underflow or the pipe queue is 3459184610Salfred * empty we schedule the transfer a few frames ahead 3460184610Salfred * of the current frame position. Else two isochronous 3461184610Salfred * transfers might overlap. 3462184610Salfred */ 3463193644Sthompsa xfer->endpoint->isoc_next = (nframes + 3) & MUSB2_MASK_FRAME; 3464193644Sthompsa xfer->endpoint->is_synced = 1; 3465193644Sthompsa DPRINTFN(2, "start next=%d\n", xfer->endpoint->isoc_next); 3466184610Salfred } 3467184610Salfred /* 3468184610Salfred * compute how many milliseconds the insertion is ahead of the 3469184610Salfred * current frame position: 3470184610Salfred */ 3471193644Sthompsa temp = (xfer->endpoint->isoc_next - nframes) & MUSB2_MASK_FRAME; 3472184610Salfred 3473184610Salfred /* 3474184610Salfred * pre-compute when the isochronous transfer will be finished: 3475184610Salfred */ 3476184610Salfred xfer->isoc_time_complete = 3477194228Sthompsa usb_isoc_time_expand(&sc->sc_bus, nframes) + temp + 3478184610Salfred fs_frames; 3479184610Salfred 3480184610Salfred /* compute frame number for next insertion */ 3481193644Sthompsa xfer->endpoint->isoc_next += fs_frames; 3482184610Salfred 3483184610Salfred /* setup TDs */ 3484184610Salfred musbotg_setup_standard_chain(xfer); 3485184610Salfred} 3486184610Salfred 3487184610Salfredstatic void 3488192984Sthompsamusbotg_device_isoc_start(struct usb_xfer *xfer) 3489184610Salfred{ 3490184610Salfred /* start TD chain */ 3491184610Salfred musbotg_start_standard_chain(xfer); 3492184610Salfred} 3493184610Salfred 3494192984Sthompsastruct usb_pipe_methods musbotg_device_isoc_methods = 3495184610Salfred{ 3496184610Salfred .open = musbotg_device_isoc_open, 3497184610Salfred .close = musbotg_device_isoc_close, 3498184610Salfred .enter = musbotg_device_isoc_enter, 3499184610Salfred .start = musbotg_device_isoc_start, 3500184610Salfred}; 3501184610Salfred 3502184610Salfred/*------------------------------------------------------------------------* 3503184610Salfred * musbotg root control support 3504184610Salfred *------------------------------------------------------------------------* 3505190735Sthompsa * Simulate a hardware HUB by handling all the necessary requests. 3506184610Salfred *------------------------------------------------------------------------*/ 3507184610Salfred 3508192984Sthompsastatic const struct usb_device_descriptor musbotg_devd = { 3509192984Sthompsa .bLength = sizeof(struct usb_device_descriptor), 3510184610Salfred .bDescriptorType = UDESC_DEVICE, 3511184610Salfred .bcdUSB = {0x00, 0x02}, 3512184610Salfred .bDeviceClass = UDCLASS_HUB, 3513184610Salfred .bDeviceSubClass = UDSUBCLASS_HUB, 3514184610Salfred .bDeviceProtocol = UDPROTO_HSHUBSTT, 3515184610Salfred .bMaxPacketSize = 64, 3516184610Salfred .bcdDevice = {0x00, 0x01}, 3517184610Salfred .iManufacturer = 1, 3518184610Salfred .iProduct = 2, 3519184610Salfred .bNumConfigurations = 1, 3520184610Salfred}; 3521184610Salfred 3522192984Sthompsastatic const struct usb_device_qualifier musbotg_odevd = { 3523192984Sthompsa .bLength = sizeof(struct usb_device_qualifier), 3524184610Salfred .bDescriptorType = UDESC_DEVICE_QUALIFIER, 3525184610Salfred .bcdUSB = {0x00, 0x02}, 3526184610Salfred .bDeviceClass = UDCLASS_HUB, 3527184610Salfred .bDeviceSubClass = UDSUBCLASS_HUB, 3528184610Salfred .bDeviceProtocol = UDPROTO_FSHUB, 3529184610Salfred .bMaxPacketSize0 = 0, 3530184610Salfred .bNumConfigurations = 0, 3531184610Salfred}; 3532184610Salfred 3533184610Salfredstatic const struct musbotg_config_desc musbotg_confd = { 3534184610Salfred .confd = { 3535192984Sthompsa .bLength = sizeof(struct usb_config_descriptor), 3536184610Salfred .bDescriptorType = UDESC_CONFIG, 3537184610Salfred .wTotalLength[0] = sizeof(musbotg_confd), 3538184610Salfred .bNumInterface = 1, 3539184610Salfred .bConfigurationValue = 1, 3540184610Salfred .iConfiguration = 0, 3541184610Salfred .bmAttributes = UC_SELF_POWERED, 3542184610Salfred .bMaxPower = 0, 3543184610Salfred }, 3544184610Salfred .ifcd = { 3545192984Sthompsa .bLength = sizeof(struct usb_interface_descriptor), 3546184610Salfred .bDescriptorType = UDESC_INTERFACE, 3547184610Salfred .bNumEndpoints = 1, 3548184610Salfred .bInterfaceClass = UICLASS_HUB, 3549184610Salfred .bInterfaceSubClass = UISUBCLASS_HUB, 3550213802Shselasky .bInterfaceProtocol = 0, 3551184610Salfred }, 3552184610Salfred .endpd = { 3553192984Sthompsa .bLength = sizeof(struct usb_endpoint_descriptor), 3554184610Salfred .bDescriptorType = UDESC_ENDPOINT, 3555184610Salfred .bEndpointAddress = (UE_DIR_IN | MUSBOTG_INTR_ENDPT), 3556184610Salfred .bmAttributes = UE_INTERRUPT, 3557184610Salfred .wMaxPacketSize[0] = 8, 3558184610Salfred .bInterval = 255, 3559184610Salfred }, 3560184610Salfred}; 3561184610Salfred 3562235000Shselasky#define HSETW(ptr, val) ptr = { (uint8_t)(val), (uint8_t)((val) >> 8) } 3563235000Shselasky 3564192984Sthompsastatic const struct usb_hub_descriptor_min musbotg_hubd = { 3565184610Salfred .bDescLength = sizeof(musbotg_hubd), 3566184610Salfred .bDescriptorType = UDESC_HUB, 3567184610Salfred .bNbrPorts = 1, 3568235000Shselasky HSETW(.wHubCharacteristics, (UHD_PWR_NO_SWITCH | UHD_OC_INDIVIDUAL)), 3569184610Salfred .bPwrOn2PwrGood = 50, 3570184610Salfred .bHubContrCurrent = 0, 3571184610Salfred .DeviceRemovable = {0}, /* port is removable */ 3572184610Salfred}; 3573184610Salfred 3574184610Salfred#define STRING_LANG \ 3575184610Salfred 0x09, 0x04, /* American English */ 3576184610Salfred 3577184610Salfred#define STRING_VENDOR \ 3578184610Salfred 'M', 0, 'e', 0, 'n', 0, 't', 0, 'o', 0, 'r', 0, ' ', 0, \ 3579184610Salfred 'G', 0, 'r', 0, 'a', 0, 'p', 0, 'h', 0, 'i', 0, 'c', 0, 's', 0 3580184610Salfred 3581184610Salfred#define STRING_PRODUCT \ 3582184610Salfred 'O', 0, 'T', 0, 'G', 0, ' ', 0, 'R', 0, \ 3583184610Salfred 'o', 0, 'o', 0, 't', 0, ' ', 0, 'H', 0, \ 3584184610Salfred 'U', 0, 'B', 0, 3585184610Salfred 3586184610SalfredUSB_MAKE_STRING_DESC(STRING_LANG, musbotg_langtab); 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; 3599257041Shselasky 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; 3779262213Sdim case UDESC_DEVICE_QUALIFIER: 3780262213Sdim if (value & 0xff) { 3781262213Sdim goto tr_stalled; 3782262213Sdim } 3783262213Sdim len = sizeof(musbotg_odevd); 3784262213Sdim ptr = (const void *)&musbotg_odevd; 3785262213Sdim goto tr_valid; 3786184610Salfred case UDESC_CONFIG: 3787184610Salfred if (value & 0xff) { 3788184610Salfred goto tr_stalled; 3789184610Salfred } 3790191402Sthompsa len = sizeof(musbotg_confd); 3791191402Sthompsa ptr = (const void *)&musbotg_confd; 3792184610Salfred goto tr_valid; 3793184610Salfred case UDESC_STRING: 3794184610Salfred switch (value & 0xff) { 3795184610Salfred case 0: /* Language table */ 3796191402Sthompsa len = sizeof(musbotg_langtab); 3797191402Sthompsa ptr = (const void *)&musbotg_langtab; 3798184610Salfred goto tr_valid; 3799184610Salfred 3800184610Salfred case 1: /* Vendor */ 3801191402Sthompsa len = sizeof(musbotg_vendor); 3802191402Sthompsa ptr = (const void *)&musbotg_vendor; 3803184610Salfred goto tr_valid; 3804184610Salfred 3805184610Salfred case 2: /* Product */ 3806191402Sthompsa len = sizeof(musbotg_product); 3807191402Sthompsa ptr = (const void *)&musbotg_product; 3808184610Salfred goto tr_valid; 3809184610Salfred default: 3810184610Salfred break; 3811184610Salfred } 3812184610Salfred break; 3813184610Salfred default: 3814184610Salfred goto tr_stalled; 3815184610Salfred } 3816184610Salfred goto tr_stalled; 3817184610Salfred 3818184610Salfredtr_handle_get_config: 3819191402Sthompsa len = 1; 3820184610Salfred sc->sc_hub_temp.wValue[0] = sc->sc_conf; 3821184610Salfred goto tr_valid; 3822184610Salfred 3823184610Salfredtr_handle_get_status: 3824191402Sthompsa len = 2; 3825184610Salfred USETW(sc->sc_hub_temp.wValue, UDS_SELF_POWERED); 3826184610Salfred goto tr_valid; 3827184610Salfred 3828184610Salfredtr_handle_set_address: 3829184610Salfred if (value & 0xFF00) { 3830184610Salfred goto tr_stalled; 3831184610Salfred } 3832184610Salfred sc->sc_rt_addr = value; 3833184610Salfred goto tr_valid; 3834184610Salfred 3835184610Salfredtr_handle_set_config: 3836184610Salfred if (value >= 2) { 3837184610Salfred goto tr_stalled; 3838184610Salfred } 3839184610Salfred sc->sc_conf = value; 3840184610Salfred goto tr_valid; 3841184610Salfred 3842184610Salfredtr_handle_get_interface: 3843191402Sthompsa len = 1; 3844184610Salfred sc->sc_hub_temp.wValue[0] = 0; 3845184610Salfred goto tr_valid; 3846184610Salfred 3847184610Salfredtr_handle_get_tt_state: 3848184610Salfredtr_handle_get_class_status: 3849184610Salfredtr_handle_get_iface_status: 3850184610Salfredtr_handle_get_ep_status: 3851191402Sthompsa len = 2; 3852184610Salfred USETW(sc->sc_hub_temp.wValue, 0); 3853184610Salfred goto tr_valid; 3854184610Salfred 3855184610Salfredtr_handle_set_halt: 3856184610Salfredtr_handle_set_interface: 3857184610Salfredtr_handle_set_wakeup: 3858184610Salfredtr_handle_clear_wakeup: 3859184610Salfredtr_handle_clear_halt: 3860184610Salfred goto tr_valid; 3861184610Salfred 3862184610Salfredtr_handle_clear_port_feature: 3863184610Salfred if (index != 1) { 3864184610Salfred goto tr_stalled; 3865184610Salfred } 3866184610Salfred DPRINTFN(8, "UR_CLEAR_PORT_FEATURE on port %d\n", index); 3867184610Salfred 3868184610Salfred switch (value) { 3869184610Salfred case UHF_PORT_SUSPEND: 3870257041Shselasky if (sc->sc_mode == MUSB2_HOST_MODE) 3871257041Shselasky musbotg_wakeup_host(sc); 3872257041Shselasky else 3873257041Shselasky musbotg_wakeup_peer(sc); 3874184610Salfred break; 3875184610Salfred 3876184610Salfred case UHF_PORT_ENABLE: 3877184610Salfred sc->sc_flags.port_enabled = 0; 3878184610Salfred break; 3879184610Salfred 3880184610Salfred case UHF_C_PORT_ENABLE: 3881257041Shselasky sc->sc_flags.change_enabled = 0; 3882257041Shselasky break; 3883257041Shselasky 3884184610Salfred case UHF_C_PORT_OVER_CURRENT: 3885257041Shselasky sc->sc_flags.change_over_current = 0; 3886257041Shselasky break; 3887257041Shselasky 3888184610Salfred case UHF_C_PORT_RESET: 3889257041Shselasky sc->sc_flags.change_reset = 0; 3890257041Shselasky break; 3891257041Shselasky 3892257041Shselasky case UHF_PORT_TEST: 3893257041Shselasky case UHF_PORT_INDICATOR: 3894184610Salfred /* nops */ 3895184610Salfred break; 3896257041Shselasky 3897184610Salfred case UHF_PORT_POWER: 3898184610Salfred sc->sc_flags.port_powered = 0; 3899184610Salfred musbotg_pull_down(sc); 3900184610Salfred musbotg_clocks_off(sc); 3901184610Salfred break; 3902184610Salfred case UHF_C_PORT_CONNECTION: 3903184610Salfred sc->sc_flags.change_connect = 0; 3904184610Salfred break; 3905184610Salfred case UHF_C_PORT_SUSPEND: 3906184610Salfred sc->sc_flags.change_suspend = 0; 3907184610Salfred break; 3908184610Salfred default: 3909191402Sthompsa err = USB_ERR_IOERROR; 3910184610Salfred goto done; 3911184610Salfred } 3912184610Salfred goto tr_valid; 3913184610Salfred 3914184610Salfredtr_handle_set_port_feature: 3915184610Salfred if (index != 1) { 3916184610Salfred goto tr_stalled; 3917184610Salfred } 3918184610Salfred DPRINTFN(8, "UR_SET_PORT_FEATURE\n"); 3919184610Salfred 3920184610Salfred switch (value) { 3921184610Salfred case UHF_PORT_ENABLE: 3922184610Salfred sc->sc_flags.port_enabled = 1; 3923184610Salfred break; 3924184610Salfred case UHF_PORT_SUSPEND: 3925257041Shselasky if (sc->sc_mode == MUSB2_HOST_MODE) 3926257041Shselasky musbotg_suspend_host(sc); 3927257041Shselasky break; 3928257041Shselasky 3929184610Salfred case UHF_PORT_RESET: 3930257041Shselasky if (sc->sc_mode == MUSB2_HOST_MODE) { 3931257041Shselasky reg = MUSB2_READ_1(sc, MUSB2_REG_POWER); 3932257041Shselasky reg |= MUSB2_MASK_RESET; 3933257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_POWER, reg); 3934257041Shselasky 3935257041Shselasky /* Wait for 20 msec */ 3936257041Shselasky usb_pause_mtx(&sc->sc_bus.bus_mtx, hz / 5); 3937257041Shselasky 3938257041Shselasky reg = MUSB2_READ_1(sc, MUSB2_REG_POWER); 3939257041Shselasky reg &= ~MUSB2_MASK_RESET; 3940257041Shselasky MUSB2_WRITE_1(sc, MUSB2_REG_POWER, reg); 3941257041Shselasky 3942257041Shselasky /* determine line speed */ 3943257041Shselasky reg = MUSB2_READ_1(sc, MUSB2_REG_POWER); 3944257041Shselasky if (reg & MUSB2_MASK_HSMODE) 3945257041Shselasky sc->sc_flags.status_high_speed = 1; 3946257041Shselasky else 3947257041Shselasky sc->sc_flags.status_high_speed = 0; 3948257041Shselasky 3949257041Shselasky sc->sc_flags.change_reset = 1; 3950257041Shselasky } else 3951257041Shselasky err = USB_ERR_IOERROR; 3952257041Shselasky break; 3953257041Shselasky 3954184610Salfred case UHF_PORT_TEST: 3955184610Salfred case UHF_PORT_INDICATOR: 3956184610Salfred /* nops */ 3957184610Salfred break; 3958184610Salfred case UHF_PORT_POWER: 3959184610Salfred sc->sc_flags.port_powered = 1; 3960184610Salfred break; 3961184610Salfred default: 3962191402Sthompsa err = USB_ERR_IOERROR; 3963184610Salfred goto done; 3964184610Salfred } 3965184610Salfred goto tr_valid; 3966184610Salfred 3967184610Salfredtr_handle_get_port_status: 3968184610Salfred 3969184610Salfred DPRINTFN(8, "UR_GET_PORT_STATUS\n"); 3970184610Salfred 3971184610Salfred if (index != 1) { 3972184610Salfred goto tr_stalled; 3973184610Salfred } 3974184610Salfred if (sc->sc_flags.status_vbus) { 3975184610Salfred musbotg_clocks_on(sc); 3976184610Salfred musbotg_pull_up(sc); 3977184610Salfred } else { 3978184610Salfred musbotg_pull_down(sc); 3979184610Salfred musbotg_clocks_off(sc); 3980184610Salfred } 3981184610Salfred 3982184610Salfred /* Select Device Side Mode */ 3983257041Shselasky if (sc->sc_mode == MUSB2_DEVICE_MODE) 3984257041Shselasky value = UPS_PORT_MODE_DEVICE; 3985257041Shselasky else 3986257041Shselasky value = 0; 3987184610Salfred 3988184610Salfred if (sc->sc_flags.status_high_speed) { 3989184610Salfred value |= UPS_HIGH_SPEED; 3990184610Salfred } 3991184610Salfred if (sc->sc_flags.port_powered) { 3992184610Salfred value |= UPS_PORT_POWER; 3993184610Salfred } 3994184610Salfred if (sc->sc_flags.port_enabled) { 3995184610Salfred value |= UPS_PORT_ENABLED; 3996184610Salfred } 3997257041Shselasky 3998257041Shselasky if (sc->sc_flags.port_over_current) 3999257041Shselasky value |= UPS_OVERCURRENT_INDICATOR; 4000257041Shselasky 4001184610Salfred if (sc->sc_flags.status_vbus && 4002184610Salfred sc->sc_flags.status_bus_reset) { 4003184610Salfred value |= UPS_CURRENT_CONNECT_STATUS; 4004184610Salfred } 4005184610Salfred if (sc->sc_flags.status_suspend) { 4006184610Salfred value |= UPS_SUSPEND; 4007184610Salfred } 4008184610Salfred USETW(sc->sc_hub_temp.ps.wPortStatus, value); 4009184610Salfred 4010184610Salfred value = 0; 4011184610Salfred 4012184610Salfred if (sc->sc_flags.change_connect) { 4013184610Salfred value |= UPS_C_CONNECT_STATUS; 4014184610Salfred 4015257041Shselasky if (sc->sc_mode == MUSB2_DEVICE_MODE) { 4016257041Shselasky if (sc->sc_flags.status_vbus && 4017257041Shselasky sc->sc_flags.status_bus_reset) { 4018257041Shselasky /* reset EP0 state */ 4019257041Shselasky sc->sc_ep0_busy = 0; 4020257041Shselasky sc->sc_ep0_cmd = 0; 4021257041Shselasky } 4022184610Salfred } 4023184610Salfred } 4024257041Shselasky if (sc->sc_flags.change_suspend) 4025184610Salfred value |= UPS_C_SUSPEND; 4026257041Shselasky if (sc->sc_flags.change_reset) 4027257041Shselasky value |= UPS_C_PORT_RESET; 4028257041Shselasky if (sc->sc_flags.change_over_current) 4029257041Shselasky value |= UPS_C_OVERCURRENT_INDICATOR; 4030257041Shselasky 4031184610Salfred USETW(sc->sc_hub_temp.ps.wPortChange, value); 4032191402Sthompsa len = sizeof(sc->sc_hub_temp.ps); 4033184610Salfred goto tr_valid; 4034184610Salfred 4035184610Salfredtr_handle_get_class_descriptor: 4036184610Salfred if (value & 0xFF) { 4037184610Salfred goto tr_stalled; 4038184610Salfred } 4039191402Sthompsa ptr = (const void *)&musbotg_hubd; 4040191402Sthompsa len = sizeof(musbotg_hubd); 4041184610Salfred goto tr_valid; 4042184610Salfred 4043184610Salfredtr_stalled: 4044191402Sthompsa err = USB_ERR_STALLED; 4045184610Salfredtr_valid: 4046184610Salfreddone: 4047191402Sthompsa *plength = len; 4048191402Sthompsa *pptr = ptr; 4049191402Sthompsa return (err); 4050184610Salfred} 4051184610Salfred 4052184610Salfredstatic void 4053192984Sthompsamusbotg_xfer_setup(struct usb_setup_params *parm) 4054184610Salfred{ 4055184610Salfred struct musbotg_softc *sc; 4056192984Sthompsa struct usb_xfer *xfer; 4057184610Salfred void *last_obj; 4058184610Salfred uint32_t ntd; 4059184610Salfred uint32_t n; 4060184610Salfred uint8_t ep_no; 4061184610Salfred 4062184610Salfred sc = MUSBOTG_BUS2SC(parm->udev->bus); 4063184610Salfred xfer = parm->curr_xfer; 4064184610Salfred 4065184610Salfred /* 4066184610Salfred * NOTE: This driver does not use any of the parameters that 4067184610Salfred * are computed from the following values. Just set some 4068184610Salfred * reasonable dummies: 4069184610Salfred */ 4070184610Salfred parm->hc_max_packet_size = 0x400; 4071257041Shselasky parm->hc_max_frame_size = 0xc00; 4072184610Salfred 4073184610Salfred if ((parm->methods == &musbotg_device_isoc_methods) || 4074184610Salfred (parm->methods == &musbotg_device_intr_methods)) 4075184610Salfred parm->hc_max_packet_count = 3; 4076184610Salfred else 4077184610Salfred parm->hc_max_packet_count = 1; 4078184610Salfred 4079194228Sthompsa usbd_transfer_setup_sub(parm); 4080184610Salfred 4081184610Salfred /* 4082184610Salfred * compute maximum number of TDs 4083184610Salfred */ 4084184610Salfred if (parm->methods == &musbotg_device_ctrl_methods) { 4085184610Salfred 4086184610Salfred ntd = xfer->nframes + 1 /* STATUS */ + 1 /* SYNC */ ; 4087184610Salfred 4088184610Salfred } else if (parm->methods == &musbotg_device_bulk_methods) { 4089184610Salfred 4090184610Salfred ntd = xfer->nframes + 1 /* SYNC */ ; 4091184610Salfred 4092184610Salfred } else if (parm->methods == &musbotg_device_intr_methods) { 4093184610Salfred 4094184610Salfred ntd = xfer->nframes + 1 /* SYNC */ ; 4095184610Salfred 4096184610Salfred } else if (parm->methods == &musbotg_device_isoc_methods) { 4097184610Salfred 4098184610Salfred ntd = xfer->nframes + 1 /* SYNC */ ; 4099184610Salfred 4100184610Salfred } else { 4101184610Salfred 4102184610Salfred ntd = 0; 4103184610Salfred } 4104184610Salfred 4105184610Salfred /* 4106194228Sthompsa * check if "usbd_transfer_setup_sub" set an error 4107184610Salfred */ 4108184610Salfred if (parm->err) { 4109184610Salfred return; 4110184610Salfred } 4111184610Salfred /* 4112184610Salfred * allocate transfer descriptors 4113184610Salfred */ 4114184610Salfred last_obj = NULL; 4115184610Salfred 4116257041Shselasky ep_no = xfer->endpointno & UE_ADDR; 4117257041Shselasky 4118184610Salfred /* 4119257041Shselasky * Check for a valid endpoint profile in USB device mode: 4120184610Salfred */ 4121257041Shselasky if (xfer->flags_int.usb_mode == USB_MODE_DEVICE) { 4122257041Shselasky const struct usb_hw_ep_profile *pf; 4123184610Salfred 4124184610Salfred musbotg_get_hw_ep_profile(parm->udev, &pf, ep_no); 4125184610Salfred 4126184610Salfred if (pf == NULL) { 4127184610Salfred /* should not happen */ 4128184610Salfred parm->err = USB_ERR_INVAL; 4129184610Salfred return; 4130184610Salfred } 4131184610Salfred } 4132184610Salfred 4133184610Salfred /* align data */ 4134184610Salfred parm->size[0] += ((-parm->size[0]) & (USB_HOST_ALIGN - 1)); 4135184610Salfred 4136184610Salfred for (n = 0; n != ntd; n++) { 4137184610Salfred 4138184610Salfred struct musbotg_td *td; 4139184610Salfred 4140184610Salfred if (parm->buf) { 4141184610Salfred 4142184610Salfred td = USB_ADD_BYTES(parm->buf, parm->size[0]); 4143184610Salfred 4144184610Salfred /* init TD */ 4145184610Salfred td->max_frame_size = xfer->max_frame_size; 4146257041Shselasky td->reg_max_packet = xfer->max_packet_size | 4147257041Shselasky ((xfer->max_packet_count - 1) << 11); 4148184610Salfred td->ep_no = ep_no; 4149184610Salfred td->obj_next = last_obj; 4150184610Salfred 4151184610Salfred last_obj = td; 4152184610Salfred } 4153184610Salfred parm->size[0] += sizeof(*td); 4154184610Salfred } 4155184610Salfred 4156184610Salfred xfer->td_start[0] = last_obj; 4157184610Salfred} 4158184610Salfred 4159184610Salfredstatic void 4160192984Sthompsamusbotg_xfer_unsetup(struct usb_xfer *xfer) 4161184610Salfred{ 4162184610Salfred return; 4163184610Salfred} 4164184610Salfred 4165184610Salfredstatic void 4166257041Shselaskymusbotg_get_dma_delay(struct usb_device *udev, uint32_t *pus) 4167257041Shselasky{ 4168257041Shselasky struct musbotg_softc *sc = MUSBOTG_BUS2SC(udev->bus); 4169257041Shselasky 4170257041Shselasky if (sc->sc_mode == MUSB2_HOST_MODE) 4171257041Shselasky *pus = 2000; /* microseconds */ 4172257041Shselasky else 4173257041Shselasky *pus = 0; 4174257041Shselasky} 4175257041Shselasky 4176257041Shselaskystatic void 4177193644Sthompsamusbotg_ep_init(struct usb_device *udev, struct usb_endpoint_descriptor *edesc, 4178193644Sthompsa struct usb_endpoint *ep) 4179184610Salfred{ 4180184610Salfred struct musbotg_softc *sc = MUSBOTG_BUS2SC(udev->bus); 4181184610Salfred 4182193644Sthompsa DPRINTFN(2, "endpoint=%p, addr=%d, endpt=%d, mode=%d (%d)\n", 4183193644Sthompsa ep, udev->address, 4184192499Sthompsa edesc->bEndpointAddress, udev->flags.usb_mode, 4185184610Salfred sc->sc_rt_addr); 4186184610Salfred 4187190735Sthompsa if (udev->device_index != sc->sc_rt_addr) { 4188184610Salfred switch (edesc->bmAttributes & UE_XFERTYPE) { 4189184610Salfred case UE_CONTROL: 4190193644Sthompsa ep->methods = &musbotg_device_ctrl_methods; 4191184610Salfred break; 4192184610Salfred case UE_INTERRUPT: 4193193644Sthompsa ep->methods = &musbotg_device_intr_methods; 4194184610Salfred break; 4195184610Salfred case UE_ISOCHRONOUS: 4196193644Sthompsa ep->methods = &musbotg_device_isoc_methods; 4197184610Salfred break; 4198184610Salfred case UE_BULK: 4199193644Sthompsa ep->methods = &musbotg_device_bulk_methods; 4200184610Salfred break; 4201184610Salfred default: 4202184610Salfred /* do nothing */ 4203184610Salfred break; 4204184610Salfred } 4205184610Salfred } 4206184610Salfred} 4207184610Salfred 4208229096Shselaskystatic void 4209229096Shselaskymusbotg_set_hw_power_sleep(struct usb_bus *bus, uint32_t state) 4210229096Shselasky{ 4211229096Shselasky struct musbotg_softc *sc = MUSBOTG_BUS2SC(bus); 4212229096Shselasky 4213229096Shselasky switch (state) { 4214229096Shselasky case USB_HW_POWER_SUSPEND: 4215229096Shselasky musbotg_suspend(sc); 4216229096Shselasky break; 4217229096Shselasky case USB_HW_POWER_SHUTDOWN: 4218229096Shselasky musbotg_uninit(sc); 4219229096Shselasky break; 4220229096Shselasky case USB_HW_POWER_RESUME: 4221229096Shselasky musbotg_resume(sc); 4222229096Shselasky break; 4223229096Shselasky default: 4224229096Shselasky break; 4225229096Shselasky } 4226229096Shselasky} 4227229096Shselasky 4228192984Sthompsastruct usb_bus_methods musbotg_bus_methods = 4229184610Salfred{ 4230193644Sthompsa .endpoint_init = &musbotg_ep_init, 4231257041Shselasky .get_dma_delay = &musbotg_get_dma_delay, 4232184610Salfred .xfer_setup = &musbotg_xfer_setup, 4233184610Salfred .xfer_unsetup = &musbotg_xfer_unsetup, 4234184610Salfred .get_hw_ep_profile = &musbotg_get_hw_ep_profile, 4235184610Salfred .set_stall = &musbotg_set_stall, 4236184610Salfred .clear_stall = &musbotg_clear_stall, 4237190735Sthompsa .roothub_exec = &musbotg_roothub_exec, 4238195960Salfred .xfer_poll = &musbotg_do_poll, 4239229096Shselasky .set_hw_power_sleep = &musbotg_set_hw_power_sleep, 4240184610Salfred}; 4241