1246122Shselasky/* $FreeBSD$ */ 2187160Sthompsa/*- 3187160Sthompsa * Copyright (c) 2009 Hans Petter Selasky. All rights reserved. 4187160Sthompsa * 5187160Sthompsa * Redistribution and use in source and binary forms, with or without 6187160Sthompsa * modification, are permitted provided that the following conditions 7187160Sthompsa * are met: 8187160Sthompsa * 1. Redistributions of source code must retain the above copyright 9187160Sthompsa * notice, this list of conditions and the following disclaimer. 10187160Sthompsa * 2. Redistributions in binary form must reproduce the above copyright 11187160Sthompsa * notice, this list of conditions and the following disclaimer in the 12187160Sthompsa * documentation and/or other materials provided with the distribution. 13187160Sthompsa * 14187160Sthompsa * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15187160Sthompsa * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16187160Sthompsa * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17187160Sthompsa * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18187160Sthompsa * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19187160Sthompsa * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20187160Sthompsa * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21187160Sthompsa * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22187160Sthompsa * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23187160Sthompsa * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24187160Sthompsa * SUCH DAMAGE. 25187160Sthompsa */ 26187160Sthompsa 27187160Sthompsa/* 28190754Sthompsa * This file contains the driver for the ATMEGA series USB OTG Controller. This 29190754Sthompsa * driver currently only supports the DCI mode of the USB hardware. 30187160Sthompsa */ 31187160Sthompsa 32187160Sthompsa/* 33187160Sthompsa * NOTE: When the chip detects BUS-reset it will also reset the 34187160Sthompsa * endpoints, Function-address and more. 35187160Sthompsa */ 36187160Sthompsa 37246122Shselasky#ifdef USB_GLOBAL_INCLUDE_FILE 38246122Shselasky#include USB_GLOBAL_INCLUDE_FILE 39246122Shselasky#else 40194677Sthompsa#include <sys/stdint.h> 41194677Sthompsa#include <sys/stddef.h> 42194677Sthompsa#include <sys/param.h> 43194677Sthompsa#include <sys/queue.h> 44194677Sthompsa#include <sys/types.h> 45194677Sthompsa#include <sys/systm.h> 46194677Sthompsa#include <sys/kernel.h> 47194677Sthompsa#include <sys/bus.h> 48194677Sthompsa#include <sys/module.h> 49194677Sthompsa#include <sys/lock.h> 50194677Sthompsa#include <sys/mutex.h> 51194677Sthompsa#include <sys/condvar.h> 52194677Sthompsa#include <sys/sysctl.h> 53194677Sthompsa#include <sys/sx.h> 54194677Sthompsa#include <sys/unistd.h> 55194677Sthompsa#include <sys/callout.h> 56194677Sthompsa#include <sys/malloc.h> 57194677Sthompsa#include <sys/priv.h> 58194677Sthompsa 59188942Sthompsa#include <dev/usb/usb.h> 60194677Sthompsa#include <dev/usb/usbdi.h> 61187160Sthompsa 62187160Sthompsa#define USB_DEBUG_VAR atmegadci_debug 63187160Sthompsa 64188942Sthompsa#include <dev/usb/usb_core.h> 65188942Sthompsa#include <dev/usb/usb_debug.h> 66188942Sthompsa#include <dev/usb/usb_busdma.h> 67188942Sthompsa#include <dev/usb/usb_process.h> 68188942Sthompsa#include <dev/usb/usb_transfer.h> 69188942Sthompsa#include <dev/usb/usb_device.h> 70188942Sthompsa#include <dev/usb/usb_hub.h> 71188942Sthompsa#include <dev/usb/usb_util.h> 72187160Sthompsa 73188942Sthompsa#include <dev/usb/usb_controller.h> 74188942Sthompsa#include <dev/usb/usb_bus.h> 75246122Shselasky#endif /* USB_GLOBAL_INCLUDE_FILE */ 76246122Shselasky 77188942Sthompsa#include <dev/usb/controller/atmegadci.h> 78187160Sthompsa 79187160Sthompsa#define ATMEGA_BUS2SC(bus) \ 80187160Sthompsa ((struct atmegadci_softc *)(((uint8_t *)(bus)) - \ 81190181Sthompsa ((uint8_t *)&(((struct atmegadci_softc *)0)->sc_bus)))) 82187160Sthompsa 83187160Sthompsa#define ATMEGA_PC2SC(pc) \ 84190180Sthompsa ATMEGA_BUS2SC(USB_DMATAG_TO_XROOT((pc)->tag_parent)->bus) 85187160Sthompsa 86194677Sthompsa#ifdef USB_DEBUG 87187160Sthompsastatic int atmegadci_debug = 0; 88187160Sthompsa 89227309Sedstatic SYSCTL_NODE(_hw_usb, OID_AUTO, atmegadci, CTLFLAG_RW, 0, 90227309Sed "USB ATMEGA DCI"); 91192502SthompsaSYSCTL_INT(_hw_usb_atmegadci, OID_AUTO, debug, CTLFLAG_RW, 92187160Sthompsa &atmegadci_debug, 0, "ATMEGA DCI debug level"); 93187160Sthompsa#endif 94187160Sthompsa 95187160Sthompsa#define ATMEGA_INTR_ENDPT 1 96187160Sthompsa 97187160Sthompsa/* prototypes */ 98187160Sthompsa 99192984Sthompsastruct usb_bus_methods atmegadci_bus_methods; 100192984Sthompsastruct usb_pipe_methods atmegadci_device_non_isoc_methods; 101192984Sthompsastruct usb_pipe_methods atmegadci_device_isoc_fs_methods; 102187160Sthompsa 103187160Sthompsastatic atmegadci_cmd_t atmegadci_setup_rx; 104187160Sthompsastatic atmegadci_cmd_t atmegadci_data_rx; 105187160Sthompsastatic atmegadci_cmd_t atmegadci_data_tx; 106187160Sthompsastatic atmegadci_cmd_t atmegadci_data_tx_sync; 107193045Sthompsastatic void atmegadci_device_done(struct usb_xfer *, usb_error_t); 108192984Sthompsastatic void atmegadci_do_poll(struct usb_bus *); 109192984Sthompsastatic void atmegadci_standard_done(struct usb_xfer *); 110190735Sthompsastatic void atmegadci_root_intr(struct atmegadci_softc *sc); 111187160Sthompsa 112187160Sthompsa/* 113187160Sthompsa * Here is a list of what the chip supports: 114187160Sthompsa */ 115192984Sthompsastatic const struct usb_hw_ep_profile 116187160Sthompsa atmegadci_ep_profile[2] = { 117187160Sthompsa 118187160Sthompsa [0] = { 119187160Sthompsa .max_in_frame_size = 64, 120187160Sthompsa .max_out_frame_size = 64, 121187160Sthompsa .is_simplex = 1, 122187160Sthompsa .support_control = 1, 123187160Sthompsa }, 124187160Sthompsa [1] = { 125187160Sthompsa .max_in_frame_size = 64, 126187160Sthompsa .max_out_frame_size = 64, 127187160Sthompsa .is_simplex = 1, 128187160Sthompsa .support_bulk = 1, 129187160Sthompsa .support_interrupt = 1, 130187160Sthompsa .support_isochronous = 1, 131187160Sthompsa .support_in = 1, 132187160Sthompsa .support_out = 1, 133187160Sthompsa }, 134187160Sthompsa}; 135187160Sthompsa 136187160Sthompsastatic void 137192984Sthompsaatmegadci_get_hw_ep_profile(struct usb_device *udev, 138192984Sthompsa const struct usb_hw_ep_profile **ppf, uint8_t ep_addr) 139187160Sthompsa{ 140187160Sthompsa if (ep_addr == 0) 141187160Sthompsa *ppf = atmegadci_ep_profile; 142187160Sthompsa else if (ep_addr < ATMEGA_EP_MAX) 143187160Sthompsa *ppf = atmegadci_ep_profile + 1; 144187160Sthompsa else 145187160Sthompsa *ppf = NULL; 146187160Sthompsa} 147187160Sthompsa 148187160Sthompsastatic void 149187160Sthompsaatmegadci_clocks_on(struct atmegadci_softc *sc) 150187160Sthompsa{ 151187160Sthompsa if (sc->sc_flags.clocks_off && 152187160Sthompsa sc->sc_flags.port_powered) { 153187160Sthompsa 154187160Sthompsa DPRINTFN(5, "\n"); 155187160Sthompsa 156187160Sthompsa /* turn on clocks */ 157187160Sthompsa (sc->sc_clocks_on) (&sc->sc_bus); 158187160Sthompsa 159187160Sthompsa ATMEGA_WRITE_1(sc, ATMEGA_USBCON, 160187160Sthompsa ATMEGA_USBCON_USBE | 161187160Sthompsa ATMEGA_USBCON_OTGPADE | 162187160Sthompsa ATMEGA_USBCON_VBUSTE); 163187160Sthompsa 164187160Sthompsa sc->sc_flags.clocks_off = 0; 165187160Sthompsa 166187160Sthompsa /* enable transceiver ? */ 167187160Sthompsa } 168187160Sthompsa} 169187160Sthompsa 170187160Sthompsastatic void 171187160Sthompsaatmegadci_clocks_off(struct atmegadci_softc *sc) 172187160Sthompsa{ 173187160Sthompsa if (!sc->sc_flags.clocks_off) { 174187160Sthompsa 175187160Sthompsa DPRINTFN(5, "\n"); 176187160Sthompsa 177187160Sthompsa /* disable Transceiver ? */ 178187160Sthompsa 179187160Sthompsa ATMEGA_WRITE_1(sc, ATMEGA_USBCON, 180187160Sthompsa ATMEGA_USBCON_USBE | 181187160Sthompsa ATMEGA_USBCON_OTGPADE | 182187160Sthompsa ATMEGA_USBCON_FRZCLK | 183187160Sthompsa ATMEGA_USBCON_VBUSTE); 184187160Sthompsa 185187160Sthompsa /* turn clocks off */ 186187160Sthompsa (sc->sc_clocks_off) (&sc->sc_bus); 187187160Sthompsa 188187160Sthompsa sc->sc_flags.clocks_off = 1; 189187160Sthompsa } 190187160Sthompsa} 191187160Sthompsa 192187160Sthompsastatic void 193187160Sthompsaatmegadci_pull_up(struct atmegadci_softc *sc) 194187160Sthompsa{ 195187160Sthompsa /* pullup D+, if possible */ 196187160Sthompsa 197187160Sthompsa if (!sc->sc_flags.d_pulled_up && 198187160Sthompsa sc->sc_flags.port_powered) { 199187160Sthompsa sc->sc_flags.d_pulled_up = 1; 200187160Sthompsa ATMEGA_WRITE_1(sc, ATMEGA_UDCON, 0); 201187160Sthompsa } 202187160Sthompsa} 203187160Sthompsa 204187160Sthompsastatic void 205187160Sthompsaatmegadci_pull_down(struct atmegadci_softc *sc) 206187160Sthompsa{ 207187160Sthompsa /* pulldown D+, if possible */ 208187160Sthompsa 209187160Sthompsa if (sc->sc_flags.d_pulled_up) { 210187160Sthompsa sc->sc_flags.d_pulled_up = 0; 211187160Sthompsa ATMEGA_WRITE_1(sc, ATMEGA_UDCON, ATMEGA_UDCON_DETACH); 212187160Sthompsa } 213187160Sthompsa} 214187160Sthompsa 215187160Sthompsastatic void 216190735Sthompsaatmegadci_wakeup_peer(struct atmegadci_softc *sc) 217187160Sthompsa{ 218187160Sthompsa uint8_t temp; 219187160Sthompsa 220187160Sthompsa if (!sc->sc_flags.status_suspend) { 221187160Sthompsa return; 222187160Sthompsa } 223187160Sthompsa 224187160Sthompsa temp = ATMEGA_READ_1(sc, ATMEGA_UDCON); 225187160Sthompsa ATMEGA_WRITE_1(sc, ATMEGA_UDCON, temp | ATMEGA_UDCON_RMWKUP); 226187160Sthompsa 227187160Sthompsa /* wait 8 milliseconds */ 228188983Sthompsa /* Wait for reset to complete. */ 229194228Sthompsa usb_pause_mtx(&sc->sc_bus.bus_mtx, hz / 125); 230187160Sthompsa 231187160Sthompsa /* hardware should have cleared RMWKUP bit */ 232187160Sthompsa} 233187160Sthompsa 234187160Sthompsastatic void 235187160Sthompsaatmegadci_set_address(struct atmegadci_softc *sc, uint8_t addr) 236187160Sthompsa{ 237187160Sthompsa DPRINTFN(5, "addr=%d\n", addr); 238187160Sthompsa 239187160Sthompsa addr |= ATMEGA_UDADDR_ADDEN; 240187160Sthompsa 241187160Sthompsa ATMEGA_WRITE_1(sc, ATMEGA_UDADDR, addr); 242187160Sthompsa} 243187160Sthompsa 244187160Sthompsastatic uint8_t 245187160Sthompsaatmegadci_setup_rx(struct atmegadci_td *td) 246187160Sthompsa{ 247187160Sthompsa struct atmegadci_softc *sc; 248192984Sthompsa struct usb_device_request req; 249187160Sthompsa uint16_t count; 250187160Sthompsa uint8_t temp; 251187160Sthompsa 252187160Sthompsa /* get pointer to softc */ 253187160Sthompsa sc = ATMEGA_PC2SC(td->pc); 254187160Sthompsa 255187160Sthompsa /* select endpoint number */ 256187160Sthompsa ATMEGA_WRITE_1(sc, ATMEGA_UENUM, td->ep_no); 257187160Sthompsa 258187160Sthompsa /* check endpoint status */ 259187160Sthompsa temp = ATMEGA_READ_1(sc, ATMEGA_UEINTX); 260187160Sthompsa 261187160Sthompsa DPRINTFN(5, "UEINTX=0x%02x\n", temp); 262187160Sthompsa 263187160Sthompsa if (!(temp & ATMEGA_UEINTX_RXSTPI)) { 264187160Sthompsa goto not_complete; 265187160Sthompsa } 266190721Sthompsa /* clear did stall */ 267190721Sthompsa td->did_stall = 0; 268187160Sthompsa /* get the packet byte count */ 269187160Sthompsa count = 270187160Sthompsa (ATMEGA_READ_1(sc, ATMEGA_UEBCHX) << 8) | 271187160Sthompsa (ATMEGA_READ_1(sc, ATMEGA_UEBCLX)); 272187160Sthompsa 273187160Sthompsa /* mask away undefined bits */ 274187160Sthompsa count &= 0x7FF; 275187160Sthompsa 276187160Sthompsa /* verify data length */ 277187160Sthompsa if (count != td->remainder) { 278187160Sthompsa DPRINTFN(0, "Invalid SETUP packet " 279187160Sthompsa "length, %d bytes\n", count); 280187160Sthompsa goto not_complete; 281187160Sthompsa } 282187160Sthompsa if (count != sizeof(req)) { 283187160Sthompsa DPRINTFN(0, "Unsupported SETUP packet " 284187160Sthompsa "length, %d bytes\n", count); 285187160Sthompsa goto not_complete; 286187160Sthompsa } 287187160Sthompsa /* receive data */ 288187160Sthompsa ATMEGA_READ_MULTI_1(sc, ATMEGA_UEDATX, 289187160Sthompsa (void *)&req, sizeof(req)); 290187160Sthompsa 291187160Sthompsa /* copy data into real buffer */ 292194228Sthompsa usbd_copy_in(td->pc, 0, &req, sizeof(req)); 293187160Sthompsa 294187160Sthompsa td->offset = sizeof(req); 295187160Sthompsa td->remainder = 0; 296187160Sthompsa 297187160Sthompsa /* sneak peek the set address */ 298187160Sthompsa if ((req.bmRequestType == UT_WRITE_DEVICE) && 299187160Sthompsa (req.bRequest == UR_SET_ADDRESS)) { 300187160Sthompsa sc->sc_dv_addr = req.wValue[0] & 0x7F; 301189677Sthompsa /* must write address before ZLP */ 302189677Sthompsa ATMEGA_WRITE_1(sc, ATMEGA_UDADDR, sc->sc_dv_addr); 303187160Sthompsa } else { 304187160Sthompsa sc->sc_dv_addr = 0xFF; 305187160Sthompsa } 306187160Sthompsa 307197556Sthompsa /* Clear SETUP packet interrupt and all other previous interrupts */ 308197556Sthompsa ATMEGA_WRITE_1(sc, ATMEGA_UEINTX, 0); 309187160Sthompsa return (0); /* complete */ 310187160Sthompsa 311187160Sthompsanot_complete: 312190721Sthompsa /* abort any ongoing transfer */ 313190721Sthompsa if (!td->did_stall) { 314190721Sthompsa DPRINTFN(5, "stalling\n"); 315190721Sthompsa ATMEGA_WRITE_1(sc, ATMEGA_UECONX, 316190721Sthompsa ATMEGA_UECONX_EPEN | 317190721Sthompsa ATMEGA_UECONX_STALLRQ); 318190721Sthompsa td->did_stall = 1; 319190721Sthompsa } 320190722Sthompsa if (temp & ATMEGA_UEINTX_RXSTPI) { 321190722Sthompsa /* clear SETUP packet interrupt */ 322190722Sthompsa ATMEGA_WRITE_1(sc, ATMEGA_UEINTX, ~ATMEGA_UEINTX_RXSTPI); 323190722Sthompsa } 324187160Sthompsa /* we only want to know if there is a SETUP packet */ 325187160Sthompsa ATMEGA_WRITE_1(sc, ATMEGA_UEIENX, ATMEGA_UEIENX_RXSTPE); 326187160Sthompsa return (1); /* not complete */ 327187160Sthompsa} 328187160Sthompsa 329187160Sthompsastatic uint8_t 330187160Sthompsaatmegadci_data_rx(struct atmegadci_td *td) 331187160Sthompsa{ 332187160Sthompsa struct atmegadci_softc *sc; 333192984Sthompsa struct usb_page_search buf_res; 334187160Sthompsa uint16_t count; 335187160Sthompsa uint8_t temp; 336187160Sthompsa uint8_t to; 337187160Sthompsa uint8_t got_short; 338187160Sthompsa 339187160Sthompsa to = 3; /* don't loop forever! */ 340187160Sthompsa got_short = 0; 341187160Sthompsa 342187160Sthompsa /* get pointer to softc */ 343187160Sthompsa sc = ATMEGA_PC2SC(td->pc); 344187160Sthompsa 345187160Sthompsa /* select endpoint number */ 346187160Sthompsa ATMEGA_WRITE_1(sc, ATMEGA_UENUM, td->ep_no); 347187160Sthompsa 348187160Sthompsarepeat: 349187160Sthompsa /* check if any of the FIFO banks have data */ 350187160Sthompsa /* check endpoint status */ 351187160Sthompsa temp = ATMEGA_READ_1(sc, ATMEGA_UEINTX); 352187160Sthompsa 353187160Sthompsa DPRINTFN(5, "temp=0x%02x rem=%u\n", temp, td->remainder); 354187160Sthompsa 355187160Sthompsa if (temp & ATMEGA_UEINTX_RXSTPI) { 356187160Sthompsa if (td->remainder == 0) { 357187160Sthompsa /* 358187160Sthompsa * We are actually complete and have 359187160Sthompsa * received the next SETUP 360187160Sthompsa */ 361187160Sthompsa DPRINTFN(5, "faking complete\n"); 362187160Sthompsa return (0); /* complete */ 363187160Sthompsa } 364187160Sthompsa /* 365187160Sthompsa * USB Host Aborted the transfer. 366187160Sthompsa */ 367187160Sthompsa td->error = 1; 368187160Sthompsa return (0); /* complete */ 369187160Sthompsa } 370187160Sthompsa /* check status */ 371187160Sthompsa if (!(temp & (ATMEGA_UEINTX_FIFOCON | 372187160Sthompsa ATMEGA_UEINTX_RXOUTI))) { 373187160Sthompsa /* no data */ 374187160Sthompsa goto not_complete; 375187160Sthompsa } 376187160Sthompsa /* get the packet byte count */ 377187160Sthompsa count = 378187160Sthompsa (ATMEGA_READ_1(sc, ATMEGA_UEBCHX) << 8) | 379187160Sthompsa (ATMEGA_READ_1(sc, ATMEGA_UEBCLX)); 380187160Sthompsa 381187160Sthompsa /* mask away undefined bits */ 382187160Sthompsa count &= 0x7FF; 383187160Sthompsa 384187160Sthompsa /* verify the packet byte count */ 385187160Sthompsa if (count != td->max_packet_size) { 386187160Sthompsa if (count < td->max_packet_size) { 387187160Sthompsa /* we have a short packet */ 388187160Sthompsa td->short_pkt = 1; 389187160Sthompsa got_short = 1; 390187160Sthompsa } else { 391187160Sthompsa /* invalid USB packet */ 392187160Sthompsa td->error = 1; 393187160Sthompsa return (0); /* we are complete */ 394187160Sthompsa } 395187160Sthompsa } 396187160Sthompsa /* verify the packet byte count */ 397187160Sthompsa if (count > td->remainder) { 398187160Sthompsa /* invalid USB packet */ 399187160Sthompsa td->error = 1; 400187160Sthompsa return (0); /* we are complete */ 401187160Sthompsa } 402187160Sthompsa while (count > 0) { 403194228Sthompsa usbd_get_page(td->pc, td->offset, &buf_res); 404187160Sthompsa 405187160Sthompsa /* get correct length */ 406187160Sthompsa if (buf_res.length > count) { 407187160Sthompsa buf_res.length = count; 408187160Sthompsa } 409187160Sthompsa /* receive data */ 410187160Sthompsa ATMEGA_READ_MULTI_1(sc, ATMEGA_UEDATX, 411187160Sthompsa buf_res.buffer, buf_res.length); 412187160Sthompsa 413187160Sthompsa /* update counters */ 414187160Sthompsa count -= buf_res.length; 415187160Sthompsa td->offset += buf_res.length; 416187160Sthompsa td->remainder -= buf_res.length; 417187160Sthompsa } 418187160Sthompsa 419187160Sthompsa /* clear OUT packet interrupt */ 420187160Sthompsa ATMEGA_WRITE_1(sc, ATMEGA_UEINTX, ATMEGA_UEINTX_RXOUTI ^ 0xFF); 421187160Sthompsa 422187160Sthompsa /* release FIFO bank */ 423187160Sthompsa ATMEGA_WRITE_1(sc, ATMEGA_UEINTX, ATMEGA_UEINTX_FIFOCON ^ 0xFF); 424187160Sthompsa 425187160Sthompsa /* check if we are complete */ 426187160Sthompsa if ((td->remainder == 0) || got_short) { 427187160Sthompsa if (td->short_pkt) { 428187160Sthompsa /* we are complete */ 429187160Sthompsa return (0); 430187160Sthompsa } 431187160Sthompsa /* else need to receive a zero length packet */ 432187160Sthompsa } 433187160Sthompsa if (--to) { 434187160Sthompsa goto repeat; 435187160Sthompsa } 436187160Sthompsanot_complete: 437187160Sthompsa /* we only want to know if there is a SETUP packet or OUT packet */ 438187160Sthompsa ATMEGA_WRITE_1(sc, ATMEGA_UEIENX, 439187160Sthompsa ATMEGA_UEIENX_RXSTPE | ATMEGA_UEIENX_RXOUTE); 440187160Sthompsa return (1); /* not complete */ 441187160Sthompsa} 442187160Sthompsa 443187160Sthompsastatic uint8_t 444187160Sthompsaatmegadci_data_tx(struct atmegadci_td *td) 445187160Sthompsa{ 446187160Sthompsa struct atmegadci_softc *sc; 447192984Sthompsa struct usb_page_search buf_res; 448187160Sthompsa uint16_t count; 449187160Sthompsa uint8_t to; 450187160Sthompsa uint8_t temp; 451187160Sthompsa 452187160Sthompsa to = 3; /* don't loop forever! */ 453187160Sthompsa 454187160Sthompsa /* get pointer to softc */ 455187160Sthompsa sc = ATMEGA_PC2SC(td->pc); 456187160Sthompsa 457187160Sthompsa /* select endpoint number */ 458187160Sthompsa ATMEGA_WRITE_1(sc, ATMEGA_UENUM, td->ep_no); 459187160Sthompsa 460187160Sthompsarepeat: 461187160Sthompsa 462187160Sthompsa /* check endpoint status */ 463187160Sthompsa temp = ATMEGA_READ_1(sc, ATMEGA_UEINTX); 464187160Sthompsa 465187160Sthompsa DPRINTFN(5, "temp=0x%02x rem=%u\n", temp, td->remainder); 466187160Sthompsa 467187160Sthompsa if (temp & ATMEGA_UEINTX_RXSTPI) { 468187160Sthompsa /* 469187160Sthompsa * The current transfer was aborted 470187160Sthompsa * by the USB Host 471187160Sthompsa */ 472187160Sthompsa td->error = 1; 473187160Sthompsa return (0); /* complete */ 474187160Sthompsa } 475191401Sthompsa 476191401Sthompsa temp = ATMEGA_READ_1(sc, ATMEGA_UESTA0X); 477191401Sthompsa if (temp & 3) { 478191401Sthompsa /* cannot write any data - a bank is busy */ 479187160Sthompsa goto not_complete; 480187160Sthompsa } 481191401Sthompsa 482187160Sthompsa count = td->max_packet_size; 483187160Sthompsa if (td->remainder < count) { 484187160Sthompsa /* we have a short packet */ 485187160Sthompsa td->short_pkt = 1; 486187160Sthompsa count = td->remainder; 487187160Sthompsa } 488187160Sthompsa while (count > 0) { 489187160Sthompsa 490194228Sthompsa usbd_get_page(td->pc, td->offset, &buf_res); 491187160Sthompsa 492187160Sthompsa /* get correct length */ 493187160Sthompsa if (buf_res.length > count) { 494187160Sthompsa buf_res.length = count; 495187160Sthompsa } 496187160Sthompsa /* transmit data */ 497187160Sthompsa ATMEGA_WRITE_MULTI_1(sc, ATMEGA_UEDATX, 498187160Sthompsa buf_res.buffer, buf_res.length); 499187160Sthompsa 500187160Sthompsa /* update counters */ 501187160Sthompsa count -= buf_res.length; 502187160Sthompsa td->offset += buf_res.length; 503187160Sthompsa td->remainder -= buf_res.length; 504187160Sthompsa } 505187160Sthompsa 506187160Sthompsa /* clear IN packet interrupt */ 507187160Sthompsa ATMEGA_WRITE_1(sc, ATMEGA_UEINTX, 0xFF ^ ATMEGA_UEINTX_TXINI); 508187160Sthompsa 509187160Sthompsa /* allocate FIFO bank */ 510187160Sthompsa ATMEGA_WRITE_1(sc, ATMEGA_UEINTX, 0xFF ^ ATMEGA_UEINTX_FIFOCON); 511187160Sthompsa 512187160Sthompsa /* check remainder */ 513187160Sthompsa if (td->remainder == 0) { 514187160Sthompsa if (td->short_pkt) { 515187160Sthompsa return (0); /* complete */ 516187160Sthompsa } 517187160Sthompsa /* else we need to transmit a short packet */ 518187160Sthompsa } 519187160Sthompsa if (--to) { 520187160Sthompsa goto repeat; 521187160Sthompsa } 522187160Sthompsanot_complete: 523187160Sthompsa /* we only want to know if there is a SETUP packet or free IN packet */ 524187160Sthompsa ATMEGA_WRITE_1(sc, ATMEGA_UEIENX, 525187160Sthompsa ATMEGA_UEIENX_RXSTPE | ATMEGA_UEIENX_TXINE); 526187160Sthompsa return (1); /* not complete */ 527187160Sthompsa} 528187160Sthompsa 529187160Sthompsastatic uint8_t 530187160Sthompsaatmegadci_data_tx_sync(struct atmegadci_td *td) 531187160Sthompsa{ 532187160Sthompsa struct atmegadci_softc *sc; 533187160Sthompsa uint8_t temp; 534187160Sthompsa 535187160Sthompsa /* get pointer to softc */ 536187160Sthompsa sc = ATMEGA_PC2SC(td->pc); 537187160Sthompsa 538187160Sthompsa /* select endpoint number */ 539187160Sthompsa ATMEGA_WRITE_1(sc, ATMEGA_UENUM, td->ep_no); 540187160Sthompsa 541187160Sthompsa /* check endpoint status */ 542187160Sthompsa temp = ATMEGA_READ_1(sc, ATMEGA_UEINTX); 543187160Sthompsa 544187160Sthompsa DPRINTFN(5, "temp=0x%02x\n", temp); 545187160Sthompsa 546187160Sthompsa if (temp & ATMEGA_UEINTX_RXSTPI) { 547187160Sthompsa DPRINTFN(5, "faking complete\n"); 548187160Sthompsa /* Race condition */ 549187160Sthompsa return (0); /* complete */ 550187160Sthompsa } 551187160Sthompsa /* 552187160Sthompsa * The control endpoint has only got one bank, so if that bank 553187160Sthompsa * is free the packet has been transferred! 554187160Sthompsa */ 555191401Sthompsa temp = ATMEGA_READ_1(sc, ATMEGA_UESTA0X); 556191401Sthompsa if (temp & 3) { 557191401Sthompsa /* cannot write any data - a bank is busy */ 558187160Sthompsa goto not_complete; 559187160Sthompsa } 560187160Sthompsa if (sc->sc_dv_addr != 0xFF) { 561187160Sthompsa /* set new address */ 562187160Sthompsa atmegadci_set_address(sc, sc->sc_dv_addr); 563187160Sthompsa } 564187160Sthompsa return (0); /* complete */ 565187160Sthompsa 566187160Sthompsanot_complete: 567187160Sthompsa /* we only want to know if there is a SETUP packet or free IN packet */ 568187160Sthompsa ATMEGA_WRITE_1(sc, ATMEGA_UEIENX, 569187160Sthompsa ATMEGA_UEIENX_RXSTPE | ATMEGA_UEIENX_TXINE); 570187160Sthompsa return (1); /* not complete */ 571187160Sthompsa} 572187160Sthompsa 573187160Sthompsastatic uint8_t 574192984Sthompsaatmegadci_xfer_do_fifo(struct usb_xfer *xfer) 575187160Sthompsa{ 576187160Sthompsa struct atmegadci_td *td; 577187160Sthompsa 578187160Sthompsa DPRINTFN(9, "\n"); 579187160Sthompsa 580187160Sthompsa td = xfer->td_transfer_cache; 581187160Sthompsa while (1) { 582187160Sthompsa if ((td->func) (td)) { 583187160Sthompsa /* operation in progress */ 584187160Sthompsa break; 585187160Sthompsa } 586187160Sthompsa if (((void *)td) == xfer->td_transfer_last) { 587187160Sthompsa goto done; 588187160Sthompsa } 589187160Sthompsa if (td->error) { 590187160Sthompsa goto done; 591187160Sthompsa } else if (td->remainder > 0) { 592187160Sthompsa /* 593187160Sthompsa * We had a short transfer. If there is no alternate 594187160Sthompsa * next, stop processing ! 595187160Sthompsa */ 596187160Sthompsa if (!td->alt_next) { 597187160Sthompsa goto done; 598187160Sthompsa } 599187160Sthompsa } 600187160Sthompsa /* 601187160Sthompsa * Fetch the next transfer descriptor and transfer 602187160Sthompsa * some flags to the next transfer descriptor 603187160Sthompsa */ 604187160Sthompsa td = td->obj_next; 605187160Sthompsa xfer->td_transfer_cache = td; 606187160Sthompsa } 607187160Sthompsa return (1); /* not complete */ 608187160Sthompsa 609187160Sthompsadone: 610187160Sthompsa /* compute all actual lengths */ 611187160Sthompsa 612187160Sthompsa atmegadci_standard_done(xfer); 613187160Sthompsa return (0); /* complete */ 614187160Sthompsa} 615187160Sthompsa 616187160Sthompsastatic void 617187160Sthompsaatmegadci_interrupt_poll(struct atmegadci_softc *sc) 618187160Sthompsa{ 619192984Sthompsa struct usb_xfer *xfer; 620187160Sthompsa 621187160Sthompsarepeat: 622187160Sthompsa TAILQ_FOREACH(xfer, &sc->sc_bus.intr_q.head, wait_entry) { 623187160Sthompsa if (!atmegadci_xfer_do_fifo(xfer)) { 624187160Sthompsa /* queue has been modified */ 625187160Sthompsa goto repeat; 626187160Sthompsa } 627187160Sthompsa } 628187160Sthompsa} 629187160Sthompsa 630187160Sthompsastatic void 631187160Sthompsaatmegadci_vbus_interrupt(struct atmegadci_softc *sc, uint8_t is_on) 632187160Sthompsa{ 633187160Sthompsa DPRINTFN(5, "vbus = %u\n", is_on); 634187160Sthompsa 635187160Sthompsa if (is_on) { 636187160Sthompsa if (!sc->sc_flags.status_vbus) { 637187160Sthompsa sc->sc_flags.status_vbus = 1; 638187160Sthompsa 639187160Sthompsa /* complete root HUB interrupt endpoint */ 640187160Sthompsa 641190735Sthompsa atmegadci_root_intr(sc); 642187160Sthompsa } 643187160Sthompsa } else { 644187160Sthompsa if (sc->sc_flags.status_vbus) { 645187160Sthompsa sc->sc_flags.status_vbus = 0; 646187160Sthompsa sc->sc_flags.status_bus_reset = 0; 647187160Sthompsa sc->sc_flags.status_suspend = 0; 648187160Sthompsa sc->sc_flags.change_suspend = 0; 649187160Sthompsa sc->sc_flags.change_connect = 1; 650187160Sthompsa 651187160Sthompsa /* complete root HUB interrupt endpoint */ 652187160Sthompsa 653190735Sthompsa atmegadci_root_intr(sc); 654187160Sthompsa } 655187160Sthompsa } 656187160Sthompsa} 657187160Sthompsa 658187160Sthompsavoid 659187160Sthompsaatmegadci_interrupt(struct atmegadci_softc *sc) 660187160Sthompsa{ 661187160Sthompsa uint8_t status; 662187160Sthompsa 663187160Sthompsa USB_BUS_LOCK(&sc->sc_bus); 664187160Sthompsa 665187160Sthompsa /* read interrupt status */ 666187160Sthompsa status = ATMEGA_READ_1(sc, ATMEGA_UDINT); 667187160Sthompsa 668187160Sthompsa /* clear all set interrupts */ 669190720Sthompsa ATMEGA_WRITE_1(sc, ATMEGA_UDINT, (~status) & 0x7D); 670187160Sthompsa 671189677Sthompsa DPRINTFN(14, "UDINT=0x%02x\n", status); 672189677Sthompsa 673187160Sthompsa /* check for any bus state change interrupts */ 674187160Sthompsa if (status & ATMEGA_UDINT_EORSTI) { 675187160Sthompsa 676187160Sthompsa DPRINTFN(5, "end of reset\n"); 677187160Sthompsa 678187160Sthompsa /* set correct state */ 679187160Sthompsa sc->sc_flags.status_bus_reset = 1; 680187160Sthompsa sc->sc_flags.status_suspend = 0; 681187160Sthompsa sc->sc_flags.change_suspend = 0; 682187160Sthompsa sc->sc_flags.change_connect = 1; 683187160Sthompsa 684187160Sthompsa /* disable resume interrupt */ 685187160Sthompsa ATMEGA_WRITE_1(sc, ATMEGA_UDIEN, 686187160Sthompsa ATMEGA_UDINT_SUSPE | 687187160Sthompsa ATMEGA_UDINT_EORSTE); 688187160Sthompsa 689187160Sthompsa /* complete root HUB interrupt endpoint */ 690190735Sthompsa atmegadci_root_intr(sc); 691187160Sthompsa } 692187160Sthompsa /* 693187160Sthompsa * If resume and suspend is set at the same time we interpret 694187160Sthompsa * that like RESUME. Resume is set when there is at least 3 695187160Sthompsa * milliseconds of inactivity on the USB BUS. 696187160Sthompsa */ 697192446Sthompsa if (status & ATMEGA_UDINT_WAKEUPI) { 698187160Sthompsa 699187160Sthompsa DPRINTFN(5, "resume interrupt\n"); 700187160Sthompsa 701187160Sthompsa if (sc->sc_flags.status_suspend) { 702187160Sthompsa /* update status bits */ 703187160Sthompsa sc->sc_flags.status_suspend = 0; 704187160Sthompsa sc->sc_flags.change_suspend = 1; 705187160Sthompsa 706187160Sthompsa /* disable resume interrupt */ 707187160Sthompsa ATMEGA_WRITE_1(sc, ATMEGA_UDIEN, 708187160Sthompsa ATMEGA_UDINT_SUSPE | 709187160Sthompsa ATMEGA_UDINT_EORSTE); 710187160Sthompsa 711187160Sthompsa /* complete root HUB interrupt endpoint */ 712190735Sthompsa atmegadci_root_intr(sc); 713187160Sthompsa } 714187160Sthompsa } else if (status & ATMEGA_UDINT_SUSPI) { 715187160Sthompsa 716187160Sthompsa DPRINTFN(5, "suspend interrupt\n"); 717187160Sthompsa 718187160Sthompsa if (!sc->sc_flags.status_suspend) { 719187160Sthompsa /* update status bits */ 720187160Sthompsa sc->sc_flags.status_suspend = 1; 721187160Sthompsa sc->sc_flags.change_suspend = 1; 722187160Sthompsa 723187160Sthompsa /* disable suspend interrupt */ 724187160Sthompsa ATMEGA_WRITE_1(sc, ATMEGA_UDIEN, 725192446Sthompsa ATMEGA_UDINT_WAKEUPE | 726187160Sthompsa ATMEGA_UDINT_EORSTE); 727187160Sthompsa 728187160Sthompsa /* complete root HUB interrupt endpoint */ 729190735Sthompsa atmegadci_root_intr(sc); 730187160Sthompsa } 731187160Sthompsa } 732187160Sthompsa /* check VBUS */ 733187160Sthompsa status = ATMEGA_READ_1(sc, ATMEGA_USBINT); 734187160Sthompsa 735187160Sthompsa /* clear all set interrupts */ 736190720Sthompsa ATMEGA_WRITE_1(sc, ATMEGA_USBINT, (~status) & 0x03); 737187160Sthompsa 738187160Sthompsa if (status & ATMEGA_USBINT_VBUSTI) { 739187160Sthompsa uint8_t temp; 740187160Sthompsa 741189677Sthompsa DPRINTFN(5, "USBINT=0x%02x\n", status); 742189677Sthompsa 743187160Sthompsa temp = ATMEGA_READ_1(sc, ATMEGA_USBSTA); 744187160Sthompsa atmegadci_vbus_interrupt(sc, temp & ATMEGA_USBSTA_VBUS); 745187160Sthompsa } 746187160Sthompsa /* check for any endpoint interrupts */ 747187160Sthompsa status = ATMEGA_READ_1(sc, ATMEGA_UEINT); 748190720Sthompsa /* the hardware will clear the UEINT bits automatically */ 749187160Sthompsa if (status) { 750187160Sthompsa 751189677Sthompsa DPRINTFN(5, "real endpoint interrupt UEINT=0x%02x\n", status); 752187160Sthompsa 753187160Sthompsa atmegadci_interrupt_poll(sc); 754187160Sthompsa } 755187160Sthompsa USB_BUS_UNLOCK(&sc->sc_bus); 756187160Sthompsa} 757187160Sthompsa 758187160Sthompsastatic void 759187160Sthompsaatmegadci_setup_standard_chain_sub(struct atmegadci_std_temp *temp) 760187160Sthompsa{ 761187160Sthompsa struct atmegadci_td *td; 762187160Sthompsa 763187160Sthompsa /* get current Transfer Descriptor */ 764187160Sthompsa td = temp->td_next; 765187160Sthompsa temp->td = td; 766187160Sthompsa 767187160Sthompsa /* prepare for next TD */ 768187160Sthompsa temp->td_next = td->obj_next; 769187160Sthompsa 770187160Sthompsa /* fill out the Transfer Descriptor */ 771187160Sthompsa td->func = temp->func; 772187160Sthompsa td->pc = temp->pc; 773187160Sthompsa td->offset = temp->offset; 774187160Sthompsa td->remainder = temp->len; 775187160Sthompsa td->error = 0; 776192552Sthompsa td->did_stall = temp->did_stall; 777187160Sthompsa td->short_pkt = temp->short_pkt; 778187160Sthompsa td->alt_next = temp->setup_alt_next; 779187160Sthompsa} 780187160Sthompsa 781187160Sthompsastatic void 782192984Sthompsaatmegadci_setup_standard_chain(struct usb_xfer *xfer) 783187160Sthompsa{ 784187160Sthompsa struct atmegadci_std_temp temp; 785187160Sthompsa struct atmegadci_softc *sc; 786187160Sthompsa struct atmegadci_td *td; 787187160Sthompsa uint32_t x; 788187160Sthompsa uint8_t ep_no; 789187160Sthompsa uint8_t need_sync; 790187160Sthompsa 791187160Sthompsa DPRINTFN(9, "addr=%d endpt=%d sumlen=%d speed=%d\n", 792193644Sthompsa xfer->address, UE_GET_ADDR(xfer->endpointno), 793194228Sthompsa xfer->sumlen, usbd_get_speed(xfer->xroot->udev)); 794187160Sthompsa 795187160Sthompsa temp.max_frame_size = xfer->max_frame_size; 796187160Sthompsa 797187160Sthompsa td = xfer->td_start[0]; 798187160Sthompsa xfer->td_transfer_first = td; 799187160Sthompsa xfer->td_transfer_cache = td; 800187160Sthompsa 801187160Sthompsa /* setup temp */ 802187160Sthompsa 803199673Sthompsa temp.pc = NULL; 804187160Sthompsa temp.td = NULL; 805187160Sthompsa temp.td_next = xfer->td_start[0]; 806190183Sthompsa temp.offset = 0; 807187160Sthompsa temp.setup_alt_next = xfer->flags_int.short_frames_ok; 808192552Sthompsa temp.did_stall = !xfer->flags_int.control_stall; 809187160Sthompsa 810187160Sthompsa sc = ATMEGA_BUS2SC(xfer->xroot->bus); 811193644Sthompsa ep_no = (xfer->endpointno & UE_ADDR); 812187160Sthompsa 813187160Sthompsa /* check if we should prepend a setup message */ 814187160Sthompsa 815187160Sthompsa if (xfer->flags_int.control_xfr) { 816187160Sthompsa if (xfer->flags_int.control_hdr) { 817187160Sthompsa 818187160Sthompsa temp.func = &atmegadci_setup_rx; 819187160Sthompsa temp.len = xfer->frlengths[0]; 820187160Sthompsa temp.pc = xfer->frbuffers + 0; 821187160Sthompsa temp.short_pkt = temp.len ? 1 : 0; 822190183Sthompsa /* check for last frame */ 823190183Sthompsa if (xfer->nframes == 1) { 824190183Sthompsa /* no STATUS stage yet, SETUP is last */ 825190183Sthompsa if (xfer->flags_int.control_act) 826190183Sthompsa temp.setup_alt_next = 0; 827190183Sthompsa } 828187160Sthompsa 829187160Sthompsa atmegadci_setup_standard_chain_sub(&temp); 830187160Sthompsa } 831187160Sthompsa x = 1; 832187160Sthompsa } else { 833187160Sthompsa x = 0; 834187160Sthompsa } 835187160Sthompsa 836187160Sthompsa if (x != xfer->nframes) { 837193644Sthompsa if (xfer->endpointno & UE_DIR_IN) { 838187160Sthompsa temp.func = &atmegadci_data_tx; 839187160Sthompsa need_sync = 1; 840187160Sthompsa } else { 841187160Sthompsa temp.func = &atmegadci_data_rx; 842187160Sthompsa need_sync = 0; 843187160Sthompsa } 844187160Sthompsa 845187160Sthompsa /* setup "pc" pointer */ 846187160Sthompsa temp.pc = xfer->frbuffers + x; 847187160Sthompsa } else { 848187160Sthompsa need_sync = 0; 849187160Sthompsa } 850187160Sthompsa while (x != xfer->nframes) { 851187160Sthompsa 852187160Sthompsa /* DATA0 / DATA1 message */ 853187160Sthompsa 854187160Sthompsa temp.len = xfer->frlengths[x]; 855187160Sthompsa 856187160Sthompsa x++; 857187160Sthompsa 858187160Sthompsa if (x == xfer->nframes) { 859190183Sthompsa if (xfer->flags_int.control_xfr) { 860190183Sthompsa if (xfer->flags_int.control_act) { 861190183Sthompsa temp.setup_alt_next = 0; 862190183Sthompsa } 863190183Sthompsa } else { 864190183Sthompsa temp.setup_alt_next = 0; 865190183Sthompsa } 866187160Sthompsa } 867187160Sthompsa if (temp.len == 0) { 868187160Sthompsa 869187160Sthompsa /* make sure that we send an USB packet */ 870187160Sthompsa 871187160Sthompsa temp.short_pkt = 0; 872187160Sthompsa 873187160Sthompsa } else { 874187160Sthompsa 875187160Sthompsa /* regular data transfer */ 876187160Sthompsa 877187160Sthompsa temp.short_pkt = (xfer->flags.force_short_xfer) ? 0 : 1; 878187160Sthompsa } 879187160Sthompsa 880187160Sthompsa atmegadci_setup_standard_chain_sub(&temp); 881187160Sthompsa 882187160Sthompsa if (xfer->flags_int.isochronous_xfr) { 883187160Sthompsa temp.offset += temp.len; 884187160Sthompsa } else { 885187160Sthompsa /* get next Page Cache pointer */ 886187160Sthompsa temp.pc = xfer->frbuffers + x; 887187160Sthompsa } 888187160Sthompsa } 889187160Sthompsa 890190183Sthompsa if (xfer->flags_int.control_xfr) { 891187160Sthompsa 892190183Sthompsa /* always setup a valid "pc" pointer for status and sync */ 893190183Sthompsa temp.pc = xfer->frbuffers + 0; 894187160Sthompsa temp.len = 0; 895187160Sthompsa temp.short_pkt = 0; 896190183Sthompsa temp.setup_alt_next = 0; 897187160Sthompsa 898190183Sthompsa /* check if we need to sync */ 899187160Sthompsa if (need_sync) { 900187160Sthompsa /* we need a SYNC point after TX */ 901187160Sthompsa temp.func = &atmegadci_data_tx_sync; 902190183Sthompsa atmegadci_setup_standard_chain_sub(&temp); 903190183Sthompsa } 904187160Sthompsa 905190183Sthompsa /* check if we should append a status stage */ 906190183Sthompsa if (!xfer->flags_int.control_act) { 907190183Sthompsa 908190183Sthompsa /* 909190183Sthompsa * Send a DATA1 message and invert the current 910190183Sthompsa * endpoint direction. 911190183Sthompsa */ 912193644Sthompsa if (xfer->endpointno & UE_DIR_IN) { 913190183Sthompsa temp.func = &atmegadci_data_rx; 914190183Sthompsa need_sync = 0; 915190183Sthompsa } else { 916190183Sthompsa temp.func = &atmegadci_data_tx; 917190183Sthompsa need_sync = 1; 918190183Sthompsa } 919190183Sthompsa 920187160Sthompsa atmegadci_setup_standard_chain_sub(&temp); 921190183Sthompsa if (need_sync) { 922190183Sthompsa /* we need a SYNC point after TX */ 923190183Sthompsa temp.func = &atmegadci_data_tx_sync; 924190183Sthompsa atmegadci_setup_standard_chain_sub(&temp); 925190183Sthompsa } 926187160Sthompsa } 927187160Sthompsa } 928187160Sthompsa /* must have at least one frame! */ 929187160Sthompsa td = temp.td; 930187160Sthompsa xfer->td_transfer_last = td; 931187160Sthompsa} 932187160Sthompsa 933187160Sthompsastatic void 934187160Sthompsaatmegadci_timeout(void *arg) 935187160Sthompsa{ 936192984Sthompsa struct usb_xfer *xfer = arg; 937187160Sthompsa 938187160Sthompsa DPRINTF("xfer=%p\n", xfer); 939187160Sthompsa 940187160Sthompsa USB_BUS_LOCK_ASSERT(xfer->xroot->bus, MA_OWNED); 941187160Sthompsa 942187160Sthompsa /* transfer is transferred */ 943187160Sthompsa atmegadci_device_done(xfer, USB_ERR_TIMEOUT); 944187160Sthompsa} 945187160Sthompsa 946187160Sthompsastatic void 947192984Sthompsaatmegadci_start_standard_chain(struct usb_xfer *xfer) 948187160Sthompsa{ 949187160Sthompsa DPRINTFN(9, "\n"); 950187160Sthompsa 951187160Sthompsa /* poll one time - will turn on interrupts */ 952187160Sthompsa if (atmegadci_xfer_do_fifo(xfer)) { 953187160Sthompsa 954187160Sthompsa /* put transfer on interrupt queue */ 955194228Sthompsa usbd_transfer_enqueue(&xfer->xroot->bus->intr_q, xfer); 956187160Sthompsa 957187160Sthompsa /* start timeout, if any */ 958187160Sthompsa if (xfer->timeout != 0) { 959194228Sthompsa usbd_transfer_timeout_ms(xfer, 960187160Sthompsa &atmegadci_timeout, xfer->timeout); 961187160Sthompsa } 962187160Sthompsa } 963187160Sthompsa} 964187160Sthompsa 965187160Sthompsastatic void 966190735Sthompsaatmegadci_root_intr(struct atmegadci_softc *sc) 967187160Sthompsa{ 968187160Sthompsa DPRINTFN(9, "\n"); 969187160Sthompsa 970187160Sthompsa USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED); 971187160Sthompsa 972187160Sthompsa /* set port bit */ 973187160Sthompsa sc->sc_hub_idata[0] = 0x02; /* we only have one port */ 974187160Sthompsa 975190735Sthompsa uhub_root_intr(&sc->sc_bus, sc->sc_hub_idata, 976190735Sthompsa sizeof(sc->sc_hub_idata)); 977190735Sthompsa } 978187160Sthompsa 979193045Sthompsastatic usb_error_t 980192984Sthompsaatmegadci_standard_done_sub(struct usb_xfer *xfer) 981187160Sthompsa{ 982187160Sthompsa struct atmegadci_td *td; 983187160Sthompsa uint32_t len; 984187160Sthompsa uint8_t error; 985187160Sthompsa 986187160Sthompsa DPRINTFN(9, "\n"); 987187160Sthompsa 988187160Sthompsa td = xfer->td_transfer_cache; 989187160Sthompsa 990187160Sthompsa do { 991187160Sthompsa len = td->remainder; 992187160Sthompsa 993187160Sthompsa if (xfer->aframes != xfer->nframes) { 994187160Sthompsa /* 995187160Sthompsa * Verify the length and subtract 996187160Sthompsa * the remainder from "frlengths[]": 997187160Sthompsa */ 998187160Sthompsa if (len > xfer->frlengths[xfer->aframes]) { 999187160Sthompsa td->error = 1; 1000187160Sthompsa } else { 1001187160Sthompsa xfer->frlengths[xfer->aframes] -= len; 1002187160Sthompsa } 1003187160Sthompsa } 1004187160Sthompsa /* Check for transfer error */ 1005187160Sthompsa if (td->error) { 1006187160Sthompsa /* the transfer is finished */ 1007187160Sthompsa error = 1; 1008187160Sthompsa td = NULL; 1009187160Sthompsa break; 1010187160Sthompsa } 1011187160Sthompsa /* Check for short transfer */ 1012187160Sthompsa if (len > 0) { 1013187160Sthompsa if (xfer->flags_int.short_frames_ok) { 1014187160Sthompsa /* follow alt next */ 1015187160Sthompsa if (td->alt_next) { 1016187160Sthompsa td = td->obj_next; 1017187160Sthompsa } else { 1018187160Sthompsa td = NULL; 1019187160Sthompsa } 1020187160Sthompsa } else { 1021187160Sthompsa /* the transfer is finished */ 1022187160Sthompsa td = NULL; 1023187160Sthompsa } 1024187160Sthompsa error = 0; 1025187160Sthompsa break; 1026187160Sthompsa } 1027187160Sthompsa td = td->obj_next; 1028187160Sthompsa 1029187160Sthompsa /* this USB frame is complete */ 1030187160Sthompsa error = 0; 1031187160Sthompsa break; 1032187160Sthompsa 1033187160Sthompsa } while (0); 1034187160Sthompsa 1035187160Sthompsa /* update transfer cache */ 1036187160Sthompsa 1037187160Sthompsa xfer->td_transfer_cache = td; 1038187160Sthompsa 1039187160Sthompsa return (error ? 1040187160Sthompsa USB_ERR_STALLED : USB_ERR_NORMAL_COMPLETION); 1041187160Sthompsa} 1042187160Sthompsa 1043187160Sthompsastatic void 1044192984Sthompsaatmegadci_standard_done(struct usb_xfer *xfer) 1045187160Sthompsa{ 1046193045Sthompsa usb_error_t err = 0; 1047187160Sthompsa 1048193644Sthompsa DPRINTFN(13, "xfer=%p endpoint=%p transfer done\n", 1049193644Sthompsa xfer, xfer->endpoint); 1050187160Sthompsa 1051187160Sthompsa /* reset scanner */ 1052187160Sthompsa 1053187160Sthompsa xfer->td_transfer_cache = xfer->td_transfer_first; 1054187160Sthompsa 1055187160Sthompsa if (xfer->flags_int.control_xfr) { 1056187160Sthompsa 1057187160Sthompsa if (xfer->flags_int.control_hdr) { 1058187160Sthompsa 1059187160Sthompsa err = atmegadci_standard_done_sub(xfer); 1060187160Sthompsa } 1061187160Sthompsa xfer->aframes = 1; 1062187160Sthompsa 1063187160Sthompsa if (xfer->td_transfer_cache == NULL) { 1064187160Sthompsa goto done; 1065187160Sthompsa } 1066187160Sthompsa } 1067187160Sthompsa while (xfer->aframes != xfer->nframes) { 1068187160Sthompsa 1069187160Sthompsa err = atmegadci_standard_done_sub(xfer); 1070187160Sthompsa xfer->aframes++; 1071187160Sthompsa 1072187160Sthompsa if (xfer->td_transfer_cache == NULL) { 1073187160Sthompsa goto done; 1074187160Sthompsa } 1075187160Sthompsa } 1076187160Sthompsa 1077187160Sthompsa if (xfer->flags_int.control_xfr && 1078187160Sthompsa !xfer->flags_int.control_act) { 1079187160Sthompsa 1080187160Sthompsa err = atmegadci_standard_done_sub(xfer); 1081187160Sthompsa } 1082187160Sthompsadone: 1083187160Sthompsa atmegadci_device_done(xfer, err); 1084187160Sthompsa} 1085187160Sthompsa 1086187160Sthompsa/*------------------------------------------------------------------------* 1087187160Sthompsa * atmegadci_device_done 1088187160Sthompsa * 1089187160Sthompsa * NOTE: this function can be called more than one time on the 1090187160Sthompsa * same USB transfer! 1091187160Sthompsa *------------------------------------------------------------------------*/ 1092187160Sthompsastatic void 1093193045Sthompsaatmegadci_device_done(struct usb_xfer *xfer, usb_error_t error) 1094187160Sthompsa{ 1095187160Sthompsa struct atmegadci_softc *sc = ATMEGA_BUS2SC(xfer->xroot->bus); 1096187160Sthompsa uint8_t ep_no; 1097187160Sthompsa 1098187160Sthompsa USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED); 1099187160Sthompsa 1100193644Sthompsa DPRINTFN(9, "xfer=%p, endpoint=%p, error=%d\n", 1101193644Sthompsa xfer, xfer->endpoint, error); 1102187160Sthompsa 1103192499Sthompsa if (xfer->flags_int.usb_mode == USB_MODE_DEVICE) { 1104193644Sthompsa ep_no = (xfer->endpointno & UE_ADDR); 1105187160Sthompsa 1106187160Sthompsa /* select endpoint number */ 1107187160Sthompsa ATMEGA_WRITE_1(sc, ATMEGA_UENUM, ep_no); 1108187160Sthompsa 1109187160Sthompsa /* disable endpoint interrupt */ 1110187160Sthompsa ATMEGA_WRITE_1(sc, ATMEGA_UEIENX, 0); 1111187160Sthompsa 1112187160Sthompsa DPRINTFN(15, "disabled interrupts!\n"); 1113187160Sthompsa } 1114187160Sthompsa /* dequeue transfer and start next transfer */ 1115194228Sthompsa usbd_transfer_done(xfer, error); 1116187160Sthompsa} 1117187160Sthompsa 1118187160Sthompsastatic void 1119239214Shselaskyatmegadci_xfer_stall(struct usb_xfer *xfer) 1120239214Shselasky{ 1121239214Shselasky atmegadci_device_done(xfer, USB_ERR_STALLED); 1122239214Shselasky} 1123239214Shselasky 1124239214Shselaskystatic void 1125239214Shselaskyatmegadci_set_stall(struct usb_device *udev, 1126195121Sthompsa struct usb_endpoint *ep, uint8_t *did_stall) 1127187160Sthompsa{ 1128187160Sthompsa struct atmegadci_softc *sc; 1129187160Sthompsa uint8_t ep_no; 1130187160Sthompsa 1131187160Sthompsa USB_BUS_LOCK_ASSERT(udev->bus, MA_OWNED); 1132187160Sthompsa 1133193644Sthompsa DPRINTFN(5, "endpoint=%p\n", ep); 1134187160Sthompsa 1135187160Sthompsa sc = ATMEGA_BUS2SC(udev->bus); 1136187160Sthompsa /* get endpoint number */ 1137193644Sthompsa ep_no = (ep->edesc->bEndpointAddress & UE_ADDR); 1138187160Sthompsa /* select endpoint number */ 1139187160Sthompsa ATMEGA_WRITE_1(sc, ATMEGA_UENUM, ep_no); 1140187160Sthompsa /* set stall */ 1141187160Sthompsa ATMEGA_WRITE_1(sc, ATMEGA_UECONX, 1142187160Sthompsa ATMEGA_UECONX_EPEN | 1143187160Sthompsa ATMEGA_UECONX_STALLRQ); 1144187160Sthompsa} 1145187160Sthompsa 1146187160Sthompsastatic void 1147187160Sthompsaatmegadci_clear_stall_sub(struct atmegadci_softc *sc, uint8_t ep_no, 1148187160Sthompsa uint8_t ep_type, uint8_t ep_dir) 1149187160Sthompsa{ 1150187160Sthompsa uint8_t temp; 1151187160Sthompsa 1152187160Sthompsa if (ep_type == UE_CONTROL) { 1153187160Sthompsa /* clearing stall is not needed */ 1154187160Sthompsa return; 1155187160Sthompsa } 1156187160Sthompsa /* select endpoint number */ 1157187160Sthompsa ATMEGA_WRITE_1(sc, ATMEGA_UENUM, ep_no); 1158187160Sthompsa 1159187160Sthompsa /* set endpoint reset */ 1160187160Sthompsa ATMEGA_WRITE_1(sc, ATMEGA_UERST, ATMEGA_UERST_MASK(ep_no)); 1161187160Sthompsa 1162187160Sthompsa /* clear endpoint reset */ 1163187160Sthompsa ATMEGA_WRITE_1(sc, ATMEGA_UERST, 0); 1164187160Sthompsa 1165187160Sthompsa /* set stall */ 1166187160Sthompsa ATMEGA_WRITE_1(sc, ATMEGA_UECONX, 1167187160Sthompsa ATMEGA_UECONX_EPEN | 1168187160Sthompsa ATMEGA_UECONX_STALLRQ); 1169187160Sthompsa 1170187160Sthompsa /* reset data toggle */ 1171187160Sthompsa ATMEGA_WRITE_1(sc, ATMEGA_UECONX, 1172187160Sthompsa ATMEGA_UECONX_EPEN | 1173187160Sthompsa ATMEGA_UECONX_RSTDT); 1174187160Sthompsa 1175187160Sthompsa /* clear stall */ 1176187160Sthompsa ATMEGA_WRITE_1(sc, ATMEGA_UECONX, 1177187160Sthompsa ATMEGA_UECONX_EPEN | 1178187160Sthompsa ATMEGA_UECONX_STALLRQC); 1179187160Sthompsa 1180189677Sthompsa do { 1181187160Sthompsa if (ep_type == UE_BULK) { 1182192446Sthompsa temp = ATMEGA_UECFG0X_EPTYPE2; 1183187160Sthompsa } else if (ep_type == UE_INTERRUPT) { 1184192446Sthompsa temp = ATMEGA_UECFG0X_EPTYPE3; 1185187160Sthompsa } else { 1186192446Sthompsa temp = ATMEGA_UECFG0X_EPTYPE1; 1187187160Sthompsa } 1188187160Sthompsa if (ep_dir & UE_DIR_IN) { 1189187160Sthompsa temp |= ATMEGA_UECFG0X_EPDIR; 1190187160Sthompsa } 1191187160Sthompsa /* two banks, 64-bytes wMaxPacket */ 1192187160Sthompsa ATMEGA_WRITE_1(sc, ATMEGA_UECFG0X, temp); 1193187160Sthompsa ATMEGA_WRITE_1(sc, ATMEGA_UECFG1X, 1194187160Sthompsa ATMEGA_UECFG1X_ALLOC | 1195191401Sthompsa ATMEGA_UECFG1X_EPBK0 | /* one bank */ 1196189677Sthompsa ATMEGA_UECFG1X_EPSIZE(3)); 1197187160Sthompsa 1198187160Sthompsa temp = ATMEGA_READ_1(sc, ATMEGA_UESTA0X); 1199187160Sthompsa if (!(temp & ATMEGA_UESTA0X_CFGOK)) { 1200199816Sthompsa device_printf(sc->sc_bus.bdev, 1201199816Sthompsa "Chip rejected configuration\n"); 1202187160Sthompsa } 1203189677Sthompsa } while (0); 1204187160Sthompsa} 1205187160Sthompsa 1206187160Sthompsastatic void 1207193644Sthompsaatmegadci_clear_stall(struct usb_device *udev, struct usb_endpoint *ep) 1208187160Sthompsa{ 1209187160Sthompsa struct atmegadci_softc *sc; 1210192984Sthompsa struct usb_endpoint_descriptor *ed; 1211187160Sthompsa 1212193644Sthompsa DPRINTFN(5, "endpoint=%p\n", ep); 1213187160Sthompsa 1214187160Sthompsa USB_BUS_LOCK_ASSERT(udev->bus, MA_OWNED); 1215187160Sthompsa 1216187160Sthompsa /* check mode */ 1217192499Sthompsa if (udev->flags.usb_mode != USB_MODE_DEVICE) { 1218187160Sthompsa /* not supported */ 1219187160Sthompsa return; 1220187160Sthompsa } 1221187160Sthompsa /* get softc */ 1222187160Sthompsa sc = ATMEGA_BUS2SC(udev->bus); 1223187160Sthompsa 1224187160Sthompsa /* get endpoint descriptor */ 1225193644Sthompsa ed = ep->edesc; 1226187160Sthompsa 1227187160Sthompsa /* reset endpoint */ 1228187160Sthompsa atmegadci_clear_stall_sub(sc, 1229187160Sthompsa (ed->bEndpointAddress & UE_ADDR), 1230187160Sthompsa (ed->bmAttributes & UE_XFERTYPE), 1231187160Sthompsa (ed->bEndpointAddress & (UE_DIR_IN | UE_DIR_OUT))); 1232187160Sthompsa} 1233187160Sthompsa 1234193045Sthompsausb_error_t 1235187160Sthompsaatmegadci_init(struct atmegadci_softc *sc) 1236187160Sthompsa{ 1237187160Sthompsa uint8_t n; 1238187160Sthompsa 1239187160Sthompsa DPRINTF("start\n"); 1240187160Sthompsa 1241187160Sthompsa /* set up the bus structure */ 1242187160Sthompsa sc->sc_bus.usbrev = USB_REV_1_1; 1243187160Sthompsa sc->sc_bus.methods = &atmegadci_bus_methods; 1244187160Sthompsa 1245187160Sthompsa USB_BUS_LOCK(&sc->sc_bus); 1246187160Sthompsa 1247192446Sthompsa /* make sure USB is enabled */ 1248192446Sthompsa ATMEGA_WRITE_1(sc, ATMEGA_USBCON, 1249192446Sthompsa ATMEGA_USBCON_USBE | 1250192446Sthompsa ATMEGA_USBCON_FRZCLK); 1251192446Sthompsa 1252187160Sthompsa /* enable USB PAD regulator */ 1253187160Sthompsa ATMEGA_WRITE_1(sc, ATMEGA_UHWCON, 1254192446Sthompsa ATMEGA_UHWCON_UVREGE | 1255192446Sthompsa ATMEGA_UHWCON_UIMOD); 1256192446Sthompsa 1257192446Sthompsa /* the following register sets up the USB PLL, assuming 16MHz X-tal */ 1258192446Sthompsa ATMEGA_WRITE_1(sc, 0x49 /* PLLCSR */, 0x14 | 0x02); 1259192446Sthompsa 1260192446Sthompsa /* wait for PLL to lock */ 1261192446Sthompsa for (n = 0; n != 20; n++) { 1262192446Sthompsa if (ATMEGA_READ_1(sc, 0x49) & 0x01) 1263192446Sthompsa break; 1264192446Sthompsa /* wait a little bit for PLL to start */ 1265194228Sthompsa usb_pause_mtx(&sc->sc_bus.bus_mtx, hz / 100); 1266192446Sthompsa } 1267192446Sthompsa 1268190720Sthompsa /* make sure USB is enabled */ 1269190720Sthompsa ATMEGA_WRITE_1(sc, ATMEGA_USBCON, 1270190720Sthompsa ATMEGA_USBCON_USBE | 1271190720Sthompsa ATMEGA_USBCON_OTGPADE | 1272190720Sthompsa ATMEGA_USBCON_VBUSTE); 1273190720Sthompsa 1274187160Sthompsa /* turn on clocks */ 1275187160Sthompsa (sc->sc_clocks_on) (&sc->sc_bus); 1276187160Sthompsa 1277189677Sthompsa /* make sure device is re-enumerated */ 1278189677Sthompsa ATMEGA_WRITE_1(sc, ATMEGA_UDCON, ATMEGA_UDCON_DETACH); 1279189677Sthompsa 1280187160Sthompsa /* wait a little for things to stabilise */ 1281194228Sthompsa usb_pause_mtx(&sc->sc_bus.bus_mtx, hz / 20); 1282187160Sthompsa 1283187160Sthompsa /* enable interrupts */ 1284187160Sthompsa ATMEGA_WRITE_1(sc, ATMEGA_UDIEN, 1285187160Sthompsa ATMEGA_UDINT_SUSPE | 1286187160Sthompsa ATMEGA_UDINT_EORSTE); 1287187160Sthompsa 1288187160Sthompsa /* reset all endpoints */ 1289187160Sthompsa ATMEGA_WRITE_1(sc, ATMEGA_UERST, 1290187160Sthompsa (1 << ATMEGA_EP_MAX) - 1); 1291187160Sthompsa 1292187160Sthompsa /* disable reset */ 1293187160Sthompsa ATMEGA_WRITE_1(sc, ATMEGA_UERST, 0); 1294187160Sthompsa 1295187160Sthompsa /* disable all endpoints */ 1296189677Sthompsa for (n = 0; n != ATMEGA_EP_MAX; n++) { 1297187160Sthompsa 1298187160Sthompsa /* select endpoint */ 1299187160Sthompsa ATMEGA_WRITE_1(sc, ATMEGA_UENUM, n); 1300187160Sthompsa 1301187160Sthompsa /* disable endpoint interrupt */ 1302187160Sthompsa ATMEGA_WRITE_1(sc, ATMEGA_UEIENX, 0); 1303187160Sthompsa 1304187160Sthompsa /* disable endpoint */ 1305187160Sthompsa ATMEGA_WRITE_1(sc, ATMEGA_UECONX, 0); 1306187160Sthompsa } 1307187160Sthompsa 1308187160Sthompsa /* turn off clocks */ 1309187160Sthompsa 1310187160Sthompsa atmegadci_clocks_off(sc); 1311187160Sthompsa 1312189677Sthompsa /* read initial VBUS state */ 1313189677Sthompsa 1314189677Sthompsa n = ATMEGA_READ_1(sc, ATMEGA_USBSTA); 1315189677Sthompsa atmegadci_vbus_interrupt(sc, n & ATMEGA_USBSTA_VBUS); 1316189677Sthompsa 1317187160Sthompsa USB_BUS_UNLOCK(&sc->sc_bus); 1318187160Sthompsa 1319187160Sthompsa /* catch any lost interrupts */ 1320187160Sthompsa 1321187160Sthompsa atmegadci_do_poll(&sc->sc_bus); 1322187160Sthompsa 1323187160Sthompsa return (0); /* success */ 1324187160Sthompsa} 1325187160Sthompsa 1326187160Sthompsavoid 1327187160Sthompsaatmegadci_uninit(struct atmegadci_softc *sc) 1328187160Sthompsa{ 1329187160Sthompsa USB_BUS_LOCK(&sc->sc_bus); 1330187160Sthompsa 1331187160Sthompsa /* turn on clocks */ 1332187160Sthompsa (sc->sc_clocks_on) (&sc->sc_bus); 1333187160Sthompsa 1334187160Sthompsa /* disable interrupts */ 1335187160Sthompsa ATMEGA_WRITE_1(sc, ATMEGA_UDIEN, 0); 1336187160Sthompsa 1337187160Sthompsa /* reset all endpoints */ 1338187160Sthompsa ATMEGA_WRITE_1(sc, ATMEGA_UERST, 1339187160Sthompsa (1 << ATMEGA_EP_MAX) - 1); 1340187160Sthompsa 1341187160Sthompsa /* disable reset */ 1342187160Sthompsa ATMEGA_WRITE_1(sc, ATMEGA_UERST, 0); 1343187160Sthompsa 1344187160Sthompsa sc->sc_flags.port_powered = 0; 1345187160Sthompsa sc->sc_flags.status_vbus = 0; 1346187160Sthompsa sc->sc_flags.status_bus_reset = 0; 1347187160Sthompsa sc->sc_flags.status_suspend = 0; 1348187160Sthompsa sc->sc_flags.change_suspend = 0; 1349187160Sthompsa sc->sc_flags.change_connect = 1; 1350187160Sthompsa 1351187160Sthompsa atmegadci_pull_down(sc); 1352187160Sthompsa atmegadci_clocks_off(sc); 1353187160Sthompsa 1354187160Sthompsa /* disable USB PAD regulator */ 1355187160Sthompsa ATMEGA_WRITE_1(sc, ATMEGA_UHWCON, 0); 1356187160Sthompsa 1357187160Sthompsa USB_BUS_UNLOCK(&sc->sc_bus); 1358187160Sthompsa} 1359187160Sthompsa 1360228483Shselaskystatic void 1361187160Sthompsaatmegadci_suspend(struct atmegadci_softc *sc) 1362187160Sthompsa{ 1363228483Shselasky /* TODO */ 1364187160Sthompsa} 1365187160Sthompsa 1366228483Shselaskystatic void 1367187160Sthompsaatmegadci_resume(struct atmegadci_softc *sc) 1368187160Sthompsa{ 1369228483Shselasky /* TODO */ 1370187160Sthompsa} 1371187160Sthompsa 1372187160Sthompsastatic void 1373192984Sthompsaatmegadci_do_poll(struct usb_bus *bus) 1374187160Sthompsa{ 1375187160Sthompsa struct atmegadci_softc *sc = ATMEGA_BUS2SC(bus); 1376187160Sthompsa 1377187160Sthompsa USB_BUS_LOCK(&sc->sc_bus); 1378187160Sthompsa atmegadci_interrupt_poll(sc); 1379187160Sthompsa USB_BUS_UNLOCK(&sc->sc_bus); 1380187160Sthompsa} 1381187160Sthompsa 1382187160Sthompsa/*------------------------------------------------------------------------* 1383187160Sthompsa * at91dci bulk support 1384187160Sthompsa * at91dci control support 1385187160Sthompsa * at91dci interrupt support 1386187160Sthompsa *------------------------------------------------------------------------*/ 1387187160Sthompsastatic void 1388192984Sthompsaatmegadci_device_non_isoc_open(struct usb_xfer *xfer) 1389187160Sthompsa{ 1390187160Sthompsa return; 1391187160Sthompsa} 1392187160Sthompsa 1393187160Sthompsastatic void 1394192984Sthompsaatmegadci_device_non_isoc_close(struct usb_xfer *xfer) 1395187160Sthompsa{ 1396187160Sthompsa atmegadci_device_done(xfer, USB_ERR_CANCELLED); 1397187160Sthompsa} 1398187160Sthompsa 1399187160Sthompsastatic void 1400192984Sthompsaatmegadci_device_non_isoc_enter(struct usb_xfer *xfer) 1401187160Sthompsa{ 1402187160Sthompsa return; 1403187160Sthompsa} 1404187160Sthompsa 1405187160Sthompsastatic void 1406192984Sthompsaatmegadci_device_non_isoc_start(struct usb_xfer *xfer) 1407187160Sthompsa{ 1408187160Sthompsa /* setup TDs */ 1409187160Sthompsa atmegadci_setup_standard_chain(xfer); 1410187160Sthompsa atmegadci_start_standard_chain(xfer); 1411187160Sthompsa} 1412187160Sthompsa 1413192984Sthompsastruct usb_pipe_methods atmegadci_device_non_isoc_methods = 1414187160Sthompsa{ 1415190737Sthompsa .open = atmegadci_device_non_isoc_open, 1416190737Sthompsa .close = atmegadci_device_non_isoc_close, 1417190737Sthompsa .enter = atmegadci_device_non_isoc_enter, 1418190737Sthompsa .start = atmegadci_device_non_isoc_start, 1419187160Sthompsa}; 1420187160Sthompsa 1421187160Sthompsa/*------------------------------------------------------------------------* 1422187160Sthompsa * at91dci full speed isochronous support 1423187160Sthompsa *------------------------------------------------------------------------*/ 1424187160Sthompsastatic void 1425192984Sthompsaatmegadci_device_isoc_fs_open(struct usb_xfer *xfer) 1426187160Sthompsa{ 1427187160Sthompsa return; 1428187160Sthompsa} 1429187160Sthompsa 1430187160Sthompsastatic void 1431192984Sthompsaatmegadci_device_isoc_fs_close(struct usb_xfer *xfer) 1432187160Sthompsa{ 1433187160Sthompsa atmegadci_device_done(xfer, USB_ERR_CANCELLED); 1434187160Sthompsa} 1435187160Sthompsa 1436187160Sthompsastatic void 1437192984Sthompsaatmegadci_device_isoc_fs_enter(struct usb_xfer *xfer) 1438187160Sthompsa{ 1439187160Sthompsa struct atmegadci_softc *sc = ATMEGA_BUS2SC(xfer->xroot->bus); 1440187160Sthompsa uint32_t temp; 1441187160Sthompsa uint32_t nframes; 1442187160Sthompsa 1443187160Sthompsa DPRINTFN(6, "xfer=%p next=%d nframes=%d\n", 1444193644Sthompsa xfer, xfer->endpoint->isoc_next, xfer->nframes); 1445187160Sthompsa 1446187160Sthompsa /* get the current frame index */ 1447187160Sthompsa 1448187160Sthompsa nframes = 1449187160Sthompsa (ATMEGA_READ_1(sc, ATMEGA_UDFNUMH) << 8) | 1450187160Sthompsa (ATMEGA_READ_1(sc, ATMEGA_UDFNUML)); 1451187160Sthompsa 1452187160Sthompsa nframes &= ATMEGA_FRAME_MASK; 1453187160Sthompsa 1454187160Sthompsa /* 1455187160Sthompsa * check if the frame index is within the window where the frames 1456187160Sthompsa * will be inserted 1457187160Sthompsa */ 1458193644Sthompsa temp = (nframes - xfer->endpoint->isoc_next) & ATMEGA_FRAME_MASK; 1459187160Sthompsa 1460193644Sthompsa if ((xfer->endpoint->is_synced == 0) || 1461187160Sthompsa (temp < xfer->nframes)) { 1462187160Sthompsa /* 1463187160Sthompsa * If there is data underflow or the pipe queue is 1464187160Sthompsa * empty we schedule the transfer a few frames ahead 1465187160Sthompsa * of the current frame position. Else two isochronous 1466187160Sthompsa * transfers might overlap. 1467187160Sthompsa */ 1468193644Sthompsa xfer->endpoint->isoc_next = (nframes + 3) & ATMEGA_FRAME_MASK; 1469193644Sthompsa xfer->endpoint->is_synced = 1; 1470193644Sthompsa DPRINTFN(3, "start next=%d\n", xfer->endpoint->isoc_next); 1471187160Sthompsa } 1472187160Sthompsa /* 1473187160Sthompsa * compute how many milliseconds the insertion is ahead of the 1474187160Sthompsa * current frame position: 1475187160Sthompsa */ 1476193644Sthompsa temp = (xfer->endpoint->isoc_next - nframes) & ATMEGA_FRAME_MASK; 1477187160Sthompsa 1478187160Sthompsa /* 1479187160Sthompsa * pre-compute when the isochronous transfer will be finished: 1480187160Sthompsa */ 1481187160Sthompsa xfer->isoc_time_complete = 1482194228Sthompsa usb_isoc_time_expand(&sc->sc_bus, nframes) + temp + 1483187160Sthompsa xfer->nframes; 1484187160Sthompsa 1485187160Sthompsa /* compute frame number for next insertion */ 1486193644Sthompsa xfer->endpoint->isoc_next += xfer->nframes; 1487187160Sthompsa 1488187160Sthompsa /* setup TDs */ 1489187160Sthompsa atmegadci_setup_standard_chain(xfer); 1490187160Sthompsa} 1491187160Sthompsa 1492187160Sthompsastatic void 1493192984Sthompsaatmegadci_device_isoc_fs_start(struct usb_xfer *xfer) 1494187160Sthompsa{ 1495187160Sthompsa /* start TD chain */ 1496187160Sthompsa atmegadci_start_standard_chain(xfer); 1497187160Sthompsa} 1498187160Sthompsa 1499192984Sthompsastruct usb_pipe_methods atmegadci_device_isoc_fs_methods = 1500187160Sthompsa{ 1501187160Sthompsa .open = atmegadci_device_isoc_fs_open, 1502187160Sthompsa .close = atmegadci_device_isoc_fs_close, 1503187160Sthompsa .enter = atmegadci_device_isoc_fs_enter, 1504187160Sthompsa .start = atmegadci_device_isoc_fs_start, 1505187160Sthompsa}; 1506187160Sthompsa 1507187160Sthompsa/*------------------------------------------------------------------------* 1508187160Sthompsa * at91dci root control support 1509187160Sthompsa *------------------------------------------------------------------------* 1510190735Sthompsa * Simulate a hardware HUB by handling all the necessary requests. 1511187160Sthompsa *------------------------------------------------------------------------*/ 1512187160Sthompsa 1513192984Sthompsastatic const struct usb_device_descriptor atmegadci_devd = { 1514192984Sthompsa .bLength = sizeof(struct usb_device_descriptor), 1515187160Sthompsa .bDescriptorType = UDESC_DEVICE, 1516187160Sthompsa .bcdUSB = {0x00, 0x02}, 1517187160Sthompsa .bDeviceClass = UDCLASS_HUB, 1518187160Sthompsa .bDeviceSubClass = UDSUBCLASS_HUB, 1519213802Shselasky .bDeviceProtocol = UDPROTO_FSHUB, 1520187160Sthompsa .bMaxPacketSize = 64, 1521187160Sthompsa .bcdDevice = {0x00, 0x01}, 1522187160Sthompsa .iManufacturer = 1, 1523187160Sthompsa .iProduct = 2, 1524187160Sthompsa .bNumConfigurations = 1, 1525187160Sthompsa}; 1526187160Sthompsa 1527187160Sthompsastatic const struct atmegadci_config_desc atmegadci_confd = { 1528187160Sthompsa .confd = { 1529192984Sthompsa .bLength = sizeof(struct usb_config_descriptor), 1530187160Sthompsa .bDescriptorType = UDESC_CONFIG, 1531187160Sthompsa .wTotalLength[0] = sizeof(atmegadci_confd), 1532187160Sthompsa .bNumInterface = 1, 1533187160Sthompsa .bConfigurationValue = 1, 1534187160Sthompsa .iConfiguration = 0, 1535187160Sthompsa .bmAttributes = UC_SELF_POWERED, 1536187160Sthompsa .bMaxPower = 0, 1537187160Sthompsa }, 1538187160Sthompsa .ifcd = { 1539192984Sthompsa .bLength = sizeof(struct usb_interface_descriptor), 1540187160Sthompsa .bDescriptorType = UDESC_INTERFACE, 1541187160Sthompsa .bNumEndpoints = 1, 1542187160Sthompsa .bInterfaceClass = UICLASS_HUB, 1543187160Sthompsa .bInterfaceSubClass = UISUBCLASS_HUB, 1544213802Shselasky .bInterfaceProtocol = 0, 1545187160Sthompsa }, 1546187160Sthompsa .endpd = { 1547192984Sthompsa .bLength = sizeof(struct usb_endpoint_descriptor), 1548187160Sthompsa .bDescriptorType = UDESC_ENDPOINT, 1549187160Sthompsa .bEndpointAddress = (UE_DIR_IN | ATMEGA_INTR_ENDPT), 1550187160Sthompsa .bmAttributes = UE_INTERRUPT, 1551187160Sthompsa .wMaxPacketSize[0] = 8, 1552187160Sthompsa .bInterval = 255, 1553187160Sthompsa }, 1554187160Sthompsa}; 1555187160Sthompsa 1556233774Shselasky#define HSETW(ptr, val) ptr = { (uint8_t)(val), (uint8_t)((val) >> 8) } 1557233774Shselasky 1558192984Sthompsastatic const struct usb_hub_descriptor_min atmegadci_hubd = { 1559187160Sthompsa .bDescLength = sizeof(atmegadci_hubd), 1560187160Sthompsa .bDescriptorType = UDESC_HUB, 1561187160Sthompsa .bNbrPorts = 1, 1562233774Shselasky HSETW(.wHubCharacteristics, (UHD_PWR_NO_SWITCH | UHD_OC_INDIVIDUAL)), 1563187160Sthompsa .bPwrOn2PwrGood = 50, 1564187160Sthompsa .bHubContrCurrent = 0, 1565187160Sthompsa .DeviceRemovable = {0}, /* port is removable */ 1566187160Sthompsa}; 1567187160Sthompsa 1568187160Sthompsa#define STRING_VENDOR \ 1569246125Shselasky "A\0T\0M\0E\0G\0A" 1570187160Sthompsa 1571187160Sthompsa#define STRING_PRODUCT \ 1572246125Shselasky "D\0C\0I\0 \0R\0o\0o\0t\0 \0H\0U\0B" 1573187160Sthompsa 1574187160SthompsaUSB_MAKE_STRING_DESC(STRING_VENDOR, atmegadci_vendor); 1575187160SthompsaUSB_MAKE_STRING_DESC(STRING_PRODUCT, atmegadci_product); 1576187160Sthompsa 1577193045Sthompsastatic usb_error_t 1578192984Sthompsaatmegadci_roothub_exec(struct usb_device *udev, 1579192984Sthompsa struct usb_device_request *req, const void **pptr, uint16_t *plength) 1580187160Sthompsa{ 1581191402Sthompsa struct atmegadci_softc *sc = ATMEGA_BUS2SC(udev->bus); 1582191402Sthompsa const void *ptr; 1583191402Sthompsa uint16_t len; 1584187160Sthompsa uint16_t value; 1585187160Sthompsa uint16_t index; 1586189677Sthompsa uint8_t temp; 1587193045Sthompsa usb_error_t err; 1588187160Sthompsa 1589187160Sthompsa USB_BUS_LOCK_ASSERT(&sc->sc_bus, MA_OWNED); 1590187160Sthompsa 1591187160Sthompsa /* buffer reset */ 1592191402Sthompsa ptr = (const void *)&sc->sc_hub_temp; 1593191402Sthompsa len = 0; 1594191402Sthompsa err = 0; 1595187160Sthompsa 1596191402Sthompsa value = UGETW(req->wValue); 1597191402Sthompsa index = UGETW(req->wIndex); 1598187160Sthompsa 1599187160Sthompsa /* demultiplex the control request */ 1600187160Sthompsa 1601191402Sthompsa switch (req->bmRequestType) { 1602187160Sthompsa case UT_READ_DEVICE: 1603191402Sthompsa switch (req->bRequest) { 1604187160Sthompsa case UR_GET_DESCRIPTOR: 1605187160Sthompsa goto tr_handle_get_descriptor; 1606187160Sthompsa case UR_GET_CONFIG: 1607187160Sthompsa goto tr_handle_get_config; 1608187160Sthompsa case UR_GET_STATUS: 1609187160Sthompsa goto tr_handle_get_status; 1610187160Sthompsa default: 1611187160Sthompsa goto tr_stalled; 1612187160Sthompsa } 1613187160Sthompsa break; 1614187160Sthompsa 1615187160Sthompsa case UT_WRITE_DEVICE: 1616191402Sthompsa switch (req->bRequest) { 1617187160Sthompsa case UR_SET_ADDRESS: 1618187160Sthompsa goto tr_handle_set_address; 1619187160Sthompsa case UR_SET_CONFIG: 1620187160Sthompsa goto tr_handle_set_config; 1621187160Sthompsa case UR_CLEAR_FEATURE: 1622187160Sthompsa goto tr_valid; /* nop */ 1623187160Sthompsa case UR_SET_DESCRIPTOR: 1624187160Sthompsa goto tr_valid; /* nop */ 1625187160Sthompsa case UR_SET_FEATURE: 1626187160Sthompsa default: 1627187160Sthompsa goto tr_stalled; 1628187160Sthompsa } 1629187160Sthompsa break; 1630187160Sthompsa 1631187160Sthompsa case UT_WRITE_ENDPOINT: 1632191402Sthompsa switch (req->bRequest) { 1633187160Sthompsa case UR_CLEAR_FEATURE: 1634191402Sthompsa switch (UGETW(req->wValue)) { 1635187160Sthompsa case UF_ENDPOINT_HALT: 1636187160Sthompsa goto tr_handle_clear_halt; 1637187160Sthompsa case UF_DEVICE_REMOTE_WAKEUP: 1638187160Sthompsa goto tr_handle_clear_wakeup; 1639187160Sthompsa default: 1640187160Sthompsa goto tr_stalled; 1641187160Sthompsa } 1642187160Sthompsa break; 1643187160Sthompsa case UR_SET_FEATURE: 1644191402Sthompsa switch (UGETW(req->wValue)) { 1645187160Sthompsa case UF_ENDPOINT_HALT: 1646187160Sthompsa goto tr_handle_set_halt; 1647187160Sthompsa case UF_DEVICE_REMOTE_WAKEUP: 1648187160Sthompsa goto tr_handle_set_wakeup; 1649187160Sthompsa default: 1650187160Sthompsa goto tr_stalled; 1651187160Sthompsa } 1652187160Sthompsa break; 1653187160Sthompsa case UR_SYNCH_FRAME: 1654187160Sthompsa goto tr_valid; /* nop */ 1655187160Sthompsa default: 1656187160Sthompsa goto tr_stalled; 1657187160Sthompsa } 1658187160Sthompsa break; 1659187160Sthompsa 1660187160Sthompsa case UT_READ_ENDPOINT: 1661191402Sthompsa switch (req->bRequest) { 1662187160Sthompsa case UR_GET_STATUS: 1663187160Sthompsa goto tr_handle_get_ep_status; 1664187160Sthompsa default: 1665187160Sthompsa goto tr_stalled; 1666187160Sthompsa } 1667187160Sthompsa break; 1668187160Sthompsa 1669187160Sthompsa case UT_WRITE_INTERFACE: 1670191402Sthompsa switch (req->bRequest) { 1671187160Sthompsa case UR_SET_INTERFACE: 1672187160Sthompsa goto tr_handle_set_interface; 1673187160Sthompsa case UR_CLEAR_FEATURE: 1674187160Sthompsa goto tr_valid; /* nop */ 1675187160Sthompsa case UR_SET_FEATURE: 1676187160Sthompsa default: 1677187160Sthompsa goto tr_stalled; 1678187160Sthompsa } 1679187160Sthompsa break; 1680187160Sthompsa 1681187160Sthompsa case UT_READ_INTERFACE: 1682191402Sthompsa switch (req->bRequest) { 1683187160Sthompsa case UR_GET_INTERFACE: 1684187160Sthompsa goto tr_handle_get_interface; 1685187160Sthompsa case UR_GET_STATUS: 1686187160Sthompsa goto tr_handle_get_iface_status; 1687187160Sthompsa default: 1688187160Sthompsa goto tr_stalled; 1689187160Sthompsa } 1690187160Sthompsa break; 1691187160Sthompsa 1692187160Sthompsa case UT_WRITE_CLASS_INTERFACE: 1693187160Sthompsa case UT_WRITE_VENDOR_INTERFACE: 1694187160Sthompsa /* XXX forward */ 1695187160Sthompsa break; 1696187160Sthompsa 1697187160Sthompsa case UT_READ_CLASS_INTERFACE: 1698187160Sthompsa case UT_READ_VENDOR_INTERFACE: 1699187160Sthompsa /* XXX forward */ 1700187160Sthompsa break; 1701187160Sthompsa 1702187160Sthompsa case UT_WRITE_CLASS_DEVICE: 1703191402Sthompsa switch (req->bRequest) { 1704187160Sthompsa case UR_CLEAR_FEATURE: 1705187160Sthompsa goto tr_valid; 1706187160Sthompsa case UR_SET_DESCRIPTOR: 1707187160Sthompsa case UR_SET_FEATURE: 1708187160Sthompsa break; 1709187160Sthompsa default: 1710187160Sthompsa goto tr_stalled; 1711187160Sthompsa } 1712187160Sthompsa break; 1713187160Sthompsa 1714187160Sthompsa case UT_WRITE_CLASS_OTHER: 1715191402Sthompsa switch (req->bRequest) { 1716187160Sthompsa case UR_CLEAR_FEATURE: 1717187160Sthompsa goto tr_handle_clear_port_feature; 1718187160Sthompsa case UR_SET_FEATURE: 1719187160Sthompsa goto tr_handle_set_port_feature; 1720187160Sthompsa case UR_CLEAR_TT_BUFFER: 1721187160Sthompsa case UR_RESET_TT: 1722187160Sthompsa case UR_STOP_TT: 1723187160Sthompsa goto tr_valid; 1724187160Sthompsa 1725187160Sthompsa default: 1726187160Sthompsa goto tr_stalled; 1727187160Sthompsa } 1728187160Sthompsa break; 1729187160Sthompsa 1730187160Sthompsa case UT_READ_CLASS_OTHER: 1731191402Sthompsa switch (req->bRequest) { 1732187160Sthompsa case UR_GET_TT_STATE: 1733187160Sthompsa goto tr_handle_get_tt_state; 1734187160Sthompsa case UR_GET_STATUS: 1735187160Sthompsa goto tr_handle_get_port_status; 1736187160Sthompsa default: 1737187160Sthompsa goto tr_stalled; 1738187160Sthompsa } 1739187160Sthompsa break; 1740187160Sthompsa 1741187160Sthompsa case UT_READ_CLASS_DEVICE: 1742191402Sthompsa switch (req->bRequest) { 1743187160Sthompsa case UR_GET_DESCRIPTOR: 1744187160Sthompsa goto tr_handle_get_class_descriptor; 1745187160Sthompsa case UR_GET_STATUS: 1746187160Sthompsa goto tr_handle_get_class_status; 1747187160Sthompsa 1748187160Sthompsa default: 1749187160Sthompsa goto tr_stalled; 1750187160Sthompsa } 1751187160Sthompsa break; 1752187160Sthompsa default: 1753187160Sthompsa goto tr_stalled; 1754187160Sthompsa } 1755187160Sthompsa goto tr_valid; 1756187160Sthompsa 1757187160Sthompsatr_handle_get_descriptor: 1758187160Sthompsa switch (value >> 8) { 1759187160Sthompsa case UDESC_DEVICE: 1760187160Sthompsa if (value & 0xff) { 1761187160Sthompsa goto tr_stalled; 1762187160Sthompsa } 1763191402Sthompsa len = sizeof(atmegadci_devd); 1764191402Sthompsa ptr = (const void *)&atmegadci_devd; 1765187160Sthompsa goto tr_valid; 1766187160Sthompsa case UDESC_CONFIG: 1767187160Sthompsa if (value & 0xff) { 1768187160Sthompsa goto tr_stalled; 1769187160Sthompsa } 1770191402Sthompsa len = sizeof(atmegadci_confd); 1771191402Sthompsa ptr = (const void *)&atmegadci_confd; 1772187160Sthompsa goto tr_valid; 1773187160Sthompsa case UDESC_STRING: 1774187160Sthompsa switch (value & 0xff) { 1775187160Sthompsa case 0: /* Language table */ 1776246123Shselasky len = sizeof(usb_string_lang_en); 1777246123Shselasky ptr = (const void *)&usb_string_lang_en; 1778187160Sthompsa goto tr_valid; 1779187160Sthompsa 1780187160Sthompsa case 1: /* Vendor */ 1781191402Sthompsa len = sizeof(atmegadci_vendor); 1782191402Sthompsa ptr = (const void *)&atmegadci_vendor; 1783187160Sthompsa goto tr_valid; 1784187160Sthompsa 1785187160Sthompsa case 2: /* Product */ 1786191402Sthompsa len = sizeof(atmegadci_product); 1787191402Sthompsa ptr = (const void *)&atmegadci_product; 1788187160Sthompsa goto tr_valid; 1789187160Sthompsa default: 1790187160Sthompsa break; 1791187160Sthompsa } 1792187160Sthompsa break; 1793187160Sthompsa default: 1794187160Sthompsa goto tr_stalled; 1795187160Sthompsa } 1796187160Sthompsa goto tr_stalled; 1797187160Sthompsa 1798187160Sthompsatr_handle_get_config: 1799191402Sthompsa len = 1; 1800187160Sthompsa sc->sc_hub_temp.wValue[0] = sc->sc_conf; 1801187160Sthompsa goto tr_valid; 1802187160Sthompsa 1803187160Sthompsatr_handle_get_status: 1804191402Sthompsa len = 2; 1805187160Sthompsa USETW(sc->sc_hub_temp.wValue, UDS_SELF_POWERED); 1806187160Sthompsa goto tr_valid; 1807187160Sthompsa 1808187160Sthompsatr_handle_set_address: 1809187160Sthompsa if (value & 0xFF00) { 1810187160Sthompsa goto tr_stalled; 1811187160Sthompsa } 1812187160Sthompsa sc->sc_rt_addr = value; 1813187160Sthompsa goto tr_valid; 1814187160Sthompsa 1815187160Sthompsatr_handle_set_config: 1816187160Sthompsa if (value >= 2) { 1817187160Sthompsa goto tr_stalled; 1818187160Sthompsa } 1819187160Sthompsa sc->sc_conf = value; 1820187160Sthompsa goto tr_valid; 1821187160Sthompsa 1822187160Sthompsatr_handle_get_interface: 1823191402Sthompsa len = 1; 1824187160Sthompsa sc->sc_hub_temp.wValue[0] = 0; 1825187160Sthompsa goto tr_valid; 1826187160Sthompsa 1827187160Sthompsatr_handle_get_tt_state: 1828187160Sthompsatr_handle_get_class_status: 1829187160Sthompsatr_handle_get_iface_status: 1830187160Sthompsatr_handle_get_ep_status: 1831191402Sthompsa len = 2; 1832187160Sthompsa USETW(sc->sc_hub_temp.wValue, 0); 1833187160Sthompsa goto tr_valid; 1834187160Sthompsa 1835187160Sthompsatr_handle_set_halt: 1836187160Sthompsatr_handle_set_interface: 1837187160Sthompsatr_handle_set_wakeup: 1838187160Sthompsatr_handle_clear_wakeup: 1839187160Sthompsatr_handle_clear_halt: 1840187160Sthompsa goto tr_valid; 1841187160Sthompsa 1842187160Sthompsatr_handle_clear_port_feature: 1843187160Sthompsa if (index != 1) { 1844187160Sthompsa goto tr_stalled; 1845187160Sthompsa } 1846187160Sthompsa DPRINTFN(9, "UR_CLEAR_PORT_FEATURE on port %d\n", index); 1847187160Sthompsa 1848187160Sthompsa switch (value) { 1849187160Sthompsa case UHF_PORT_SUSPEND: 1850190735Sthompsa atmegadci_wakeup_peer(sc); 1851187160Sthompsa break; 1852187160Sthompsa 1853187160Sthompsa case UHF_PORT_ENABLE: 1854187160Sthompsa sc->sc_flags.port_enabled = 0; 1855187160Sthompsa break; 1856187160Sthompsa 1857187160Sthompsa case UHF_PORT_TEST: 1858187160Sthompsa case UHF_PORT_INDICATOR: 1859187160Sthompsa case UHF_C_PORT_ENABLE: 1860187160Sthompsa case UHF_C_PORT_OVER_CURRENT: 1861187160Sthompsa case UHF_C_PORT_RESET: 1862187160Sthompsa /* nops */ 1863187160Sthompsa break; 1864187160Sthompsa case UHF_PORT_POWER: 1865187160Sthompsa sc->sc_flags.port_powered = 0; 1866187160Sthompsa atmegadci_pull_down(sc); 1867187160Sthompsa atmegadci_clocks_off(sc); 1868187160Sthompsa break; 1869187160Sthompsa case UHF_C_PORT_CONNECTION: 1870189677Sthompsa /* clear connect change flag */ 1871187160Sthompsa sc->sc_flags.change_connect = 0; 1872189677Sthompsa 1873192446Sthompsa if (!sc->sc_flags.status_bus_reset) { 1874192446Sthompsa /* we are not connected */ 1875192446Sthompsa break; 1876192446Sthompsa } 1877192446Sthompsa 1878189677Sthompsa /* configure the control endpoint */ 1879189677Sthompsa 1880189677Sthompsa /* select endpoint number */ 1881189677Sthompsa ATMEGA_WRITE_1(sc, ATMEGA_UENUM, 0); 1882189677Sthompsa 1883189677Sthompsa /* set endpoint reset */ 1884189677Sthompsa ATMEGA_WRITE_1(sc, ATMEGA_UERST, ATMEGA_UERST_MASK(0)); 1885189677Sthompsa 1886189677Sthompsa /* clear endpoint reset */ 1887189677Sthompsa ATMEGA_WRITE_1(sc, ATMEGA_UERST, 0); 1888189677Sthompsa 1889189677Sthompsa /* enable and stall endpoint */ 1890189677Sthompsa ATMEGA_WRITE_1(sc, ATMEGA_UECONX, 1891189677Sthompsa ATMEGA_UECONX_EPEN | 1892189677Sthompsa ATMEGA_UECONX_STALLRQ); 1893189677Sthompsa 1894189677Sthompsa /* one bank, 64-bytes wMaxPacket */ 1895189677Sthompsa ATMEGA_WRITE_1(sc, ATMEGA_UECFG0X, 1896189677Sthompsa ATMEGA_UECFG0X_EPTYPE0); 1897189677Sthompsa ATMEGA_WRITE_1(sc, ATMEGA_UECFG1X, 1898189677Sthompsa ATMEGA_UECFG1X_ALLOC | 1899189677Sthompsa ATMEGA_UECFG1X_EPBK0 | 1900189677Sthompsa ATMEGA_UECFG1X_EPSIZE(3)); 1901189677Sthompsa 1902189677Sthompsa /* check valid config */ 1903189677Sthompsa temp = ATMEGA_READ_1(sc, ATMEGA_UESTA0X); 1904189677Sthompsa if (!(temp & ATMEGA_UESTA0X_CFGOK)) { 1905199816Sthompsa device_printf(sc->sc_bus.bdev, 1906199816Sthompsa "Chip rejected EP0 configuration\n"); 1907189677Sthompsa } 1908187160Sthompsa break; 1909187160Sthompsa case UHF_C_PORT_SUSPEND: 1910187160Sthompsa sc->sc_flags.change_suspend = 0; 1911187160Sthompsa break; 1912187160Sthompsa default: 1913191402Sthompsa err = USB_ERR_IOERROR; 1914187160Sthompsa goto done; 1915187160Sthompsa } 1916187160Sthompsa goto tr_valid; 1917187160Sthompsa 1918187160Sthompsatr_handle_set_port_feature: 1919187160Sthompsa if (index != 1) { 1920187160Sthompsa goto tr_stalled; 1921187160Sthompsa } 1922187160Sthompsa DPRINTFN(9, "UR_SET_PORT_FEATURE\n"); 1923187160Sthompsa 1924187160Sthompsa switch (value) { 1925187160Sthompsa case UHF_PORT_ENABLE: 1926187160Sthompsa sc->sc_flags.port_enabled = 1; 1927187160Sthompsa break; 1928187160Sthompsa case UHF_PORT_SUSPEND: 1929187160Sthompsa case UHF_PORT_RESET: 1930187160Sthompsa case UHF_PORT_TEST: 1931187160Sthompsa case UHF_PORT_INDICATOR: 1932187160Sthompsa /* nops */ 1933187160Sthompsa break; 1934187160Sthompsa case UHF_PORT_POWER: 1935187160Sthompsa sc->sc_flags.port_powered = 1; 1936187160Sthompsa break; 1937187160Sthompsa default: 1938191402Sthompsa err = USB_ERR_IOERROR; 1939187160Sthompsa goto done; 1940187160Sthompsa } 1941187160Sthompsa goto tr_valid; 1942187160Sthompsa 1943187160Sthompsatr_handle_get_port_status: 1944187160Sthompsa 1945187160Sthompsa DPRINTFN(9, "UR_GET_PORT_STATUS\n"); 1946187160Sthompsa 1947187160Sthompsa if (index != 1) { 1948187160Sthompsa goto tr_stalled; 1949187160Sthompsa } 1950187160Sthompsa if (sc->sc_flags.status_vbus) { 1951187160Sthompsa atmegadci_clocks_on(sc); 1952187160Sthompsa atmegadci_pull_up(sc); 1953187160Sthompsa } else { 1954187160Sthompsa atmegadci_pull_down(sc); 1955187160Sthompsa atmegadci_clocks_off(sc); 1956187160Sthompsa } 1957187160Sthompsa 1958187160Sthompsa /* Select FULL-speed and Device Side Mode */ 1959187160Sthompsa 1960187160Sthompsa value = UPS_PORT_MODE_DEVICE; 1961187160Sthompsa 1962187160Sthompsa if (sc->sc_flags.port_powered) { 1963187160Sthompsa value |= UPS_PORT_POWER; 1964187160Sthompsa } 1965187160Sthompsa if (sc->sc_flags.port_enabled) { 1966187160Sthompsa value |= UPS_PORT_ENABLED; 1967187160Sthompsa } 1968187160Sthompsa if (sc->sc_flags.status_vbus && 1969187160Sthompsa sc->sc_flags.status_bus_reset) { 1970187160Sthompsa value |= UPS_CURRENT_CONNECT_STATUS; 1971187160Sthompsa } 1972187160Sthompsa if (sc->sc_flags.status_suspend) { 1973187160Sthompsa value |= UPS_SUSPEND; 1974187160Sthompsa } 1975187160Sthompsa USETW(sc->sc_hub_temp.ps.wPortStatus, value); 1976187160Sthompsa 1977187160Sthompsa value = 0; 1978187160Sthompsa 1979187160Sthompsa if (sc->sc_flags.change_connect) { 1980187160Sthompsa value |= UPS_C_CONNECT_STATUS; 1981187160Sthompsa } 1982187160Sthompsa if (sc->sc_flags.change_suspend) { 1983187160Sthompsa value |= UPS_C_SUSPEND; 1984187160Sthompsa } 1985187160Sthompsa USETW(sc->sc_hub_temp.ps.wPortChange, value); 1986191402Sthompsa len = sizeof(sc->sc_hub_temp.ps); 1987187160Sthompsa goto tr_valid; 1988187160Sthompsa 1989187160Sthompsatr_handle_get_class_descriptor: 1990187160Sthompsa if (value & 0xFF) { 1991187160Sthompsa goto tr_stalled; 1992187160Sthompsa } 1993191402Sthompsa ptr = (const void *)&atmegadci_hubd; 1994191402Sthompsa len = sizeof(atmegadci_hubd); 1995187160Sthompsa goto tr_valid; 1996187160Sthompsa 1997187160Sthompsatr_stalled: 1998191402Sthompsa err = USB_ERR_STALLED; 1999187160Sthompsatr_valid: 2000187160Sthompsadone: 2001191402Sthompsa *plength = len; 2002191402Sthompsa *pptr = ptr; 2003191402Sthompsa return (err); 2004187160Sthompsa} 2005187160Sthompsa 2006187160Sthompsastatic void 2007192984Sthompsaatmegadci_xfer_setup(struct usb_setup_params *parm) 2008187160Sthompsa{ 2009192984Sthompsa const struct usb_hw_ep_profile *pf; 2010187160Sthompsa struct atmegadci_softc *sc; 2011192984Sthompsa struct usb_xfer *xfer; 2012187160Sthompsa void *last_obj; 2013187160Sthompsa uint32_t ntd; 2014187160Sthompsa uint32_t n; 2015187160Sthompsa uint8_t ep_no; 2016187160Sthompsa 2017187160Sthompsa sc = ATMEGA_BUS2SC(parm->udev->bus); 2018187160Sthompsa xfer = parm->curr_xfer; 2019187160Sthompsa 2020187160Sthompsa /* 2021187160Sthompsa * NOTE: This driver does not use any of the parameters that 2022187160Sthompsa * are computed from the following values. Just set some 2023187160Sthompsa * reasonable dummies: 2024187160Sthompsa */ 2025187160Sthompsa parm->hc_max_packet_size = 0x500; 2026187160Sthompsa parm->hc_max_packet_count = 1; 2027187160Sthompsa parm->hc_max_frame_size = 0x500; 2028187160Sthompsa 2029194228Sthompsa usbd_transfer_setup_sub(parm); 2030187160Sthompsa 2031187160Sthompsa /* 2032187160Sthompsa * compute maximum number of TDs 2033187160Sthompsa */ 2034193644Sthompsa if ((xfer->endpoint->edesc->bmAttributes & UE_XFERTYPE) == UE_CONTROL) { 2035187160Sthompsa 2036190737Sthompsa ntd = xfer->nframes + 1 /* STATUS */ + 1 /* SYNC 1 */ 2037187160Sthompsa + 1 /* SYNC 2 */ ; 2038190737Sthompsa } else { 2039187160Sthompsa 2040187160Sthompsa ntd = xfer->nframes + 1 /* SYNC */ ; 2041187160Sthompsa } 2042187160Sthompsa 2043187160Sthompsa /* 2044194228Sthompsa * check if "usbd_transfer_setup_sub" set an error 2045187160Sthompsa */ 2046190737Sthompsa if (parm->err) 2047187160Sthompsa return; 2048190737Sthompsa 2049187160Sthompsa /* 2050187160Sthompsa * allocate transfer descriptors 2051187160Sthompsa */ 2052187160Sthompsa last_obj = NULL; 2053187160Sthompsa 2054187160Sthompsa /* 2055187160Sthompsa * get profile stuff 2056187160Sthompsa */ 2057193644Sthompsa ep_no = xfer->endpointno & UE_ADDR; 2058190737Sthompsa atmegadci_get_hw_ep_profile(parm->udev, &pf, ep_no); 2059187160Sthompsa 2060190737Sthompsa if (pf == NULL) { 2061190737Sthompsa /* should not happen */ 2062190737Sthompsa parm->err = USB_ERR_INVAL; 2063190737Sthompsa return; 2064187160Sthompsa } 2065187160Sthompsa 2066187160Sthompsa /* align data */ 2067187160Sthompsa parm->size[0] += ((-parm->size[0]) & (USB_HOST_ALIGN - 1)); 2068187160Sthompsa 2069187160Sthompsa for (n = 0; n != ntd; n++) { 2070187160Sthompsa 2071187160Sthompsa struct atmegadci_td *td; 2072187160Sthompsa 2073187160Sthompsa if (parm->buf) { 2074187160Sthompsa 2075187160Sthompsa td = USB_ADD_BYTES(parm->buf, parm->size[0]); 2076187160Sthompsa 2077187160Sthompsa /* init TD */ 2078187160Sthompsa td->max_packet_size = xfer->max_packet_size; 2079187160Sthompsa td->ep_no = ep_no; 2080187160Sthompsa if (pf->support_multi_buffer) { 2081187160Sthompsa td->support_multi_buffer = 1; 2082187160Sthompsa } 2083187160Sthompsa td->obj_next = last_obj; 2084187160Sthompsa 2085187160Sthompsa last_obj = td; 2086187160Sthompsa } 2087187160Sthompsa parm->size[0] += sizeof(*td); 2088187160Sthompsa } 2089187160Sthompsa 2090187160Sthompsa xfer->td_start[0] = last_obj; 2091187160Sthompsa} 2092187160Sthompsa 2093187160Sthompsastatic void 2094192984Sthompsaatmegadci_xfer_unsetup(struct usb_xfer *xfer) 2095187160Sthompsa{ 2096187160Sthompsa return; 2097187160Sthompsa} 2098187160Sthompsa 2099187160Sthompsastatic void 2100193644Sthompsaatmegadci_ep_init(struct usb_device *udev, struct usb_endpoint_descriptor *edesc, 2101193644Sthompsa struct usb_endpoint *ep) 2102187160Sthompsa{ 2103187160Sthompsa struct atmegadci_softc *sc = ATMEGA_BUS2SC(udev->bus); 2104187160Sthompsa 2105193644Sthompsa DPRINTFN(2, "endpoint=%p, addr=%d, endpt=%d, mode=%d (%d,%d)\n", 2106193644Sthompsa ep, udev->address, 2107192499Sthompsa edesc->bEndpointAddress, udev->flags.usb_mode, 2108189677Sthompsa sc->sc_rt_addr, udev->device_index); 2109187160Sthompsa 2110190735Sthompsa if (udev->device_index != sc->sc_rt_addr) { 2111187160Sthompsa 2112187160Sthompsa if (udev->speed != USB_SPEED_FULL) { 2113187160Sthompsa /* not supported */ 2114187160Sthompsa return; 2115187160Sthompsa } 2116190737Sthompsa if ((edesc->bmAttributes & UE_XFERTYPE) == UE_ISOCHRONOUS) 2117193644Sthompsa ep->methods = &atmegadci_device_isoc_fs_methods; 2118190737Sthompsa else 2119193644Sthompsa ep->methods = &atmegadci_device_non_isoc_methods; 2120187160Sthompsa } 2121187160Sthompsa} 2122187160Sthompsa 2123228483Shselaskystatic void 2124228483Shselaskyatmegadci_set_hw_power_sleep(struct usb_bus *bus, uint32_t state) 2125228483Shselasky{ 2126228483Shselasky struct atmegadci_softc *sc = ATMEGA_BUS2SC(bus); 2127228483Shselasky 2128228483Shselasky switch (state) { 2129228483Shselasky case USB_HW_POWER_SUSPEND: 2130228483Shselasky atmegadci_suspend(sc); 2131228483Shselasky break; 2132228483Shselasky case USB_HW_POWER_SHUTDOWN: 2133228483Shselasky atmegadci_uninit(sc); 2134228483Shselasky break; 2135228483Shselasky case USB_HW_POWER_RESUME: 2136228483Shselasky atmegadci_resume(sc); 2137228483Shselasky break; 2138228483Shselasky default: 2139228483Shselasky break; 2140228483Shselasky } 2141228483Shselasky} 2142228483Shselasky 2143192984Sthompsastruct usb_bus_methods atmegadci_bus_methods = 2144187160Sthompsa{ 2145193644Sthompsa .endpoint_init = &atmegadci_ep_init, 2146187160Sthompsa .xfer_setup = &atmegadci_xfer_setup, 2147187160Sthompsa .xfer_unsetup = &atmegadci_xfer_unsetup, 2148187160Sthompsa .get_hw_ep_profile = &atmegadci_get_hw_ep_profile, 2149239214Shselasky .xfer_stall = &atmegadci_xfer_stall, 2150187160Sthompsa .set_stall = &atmegadci_set_stall, 2151187160Sthompsa .clear_stall = &atmegadci_clear_stall, 2152190735Sthompsa .roothub_exec = &atmegadci_roothub_exec, 2153195960Salfred .xfer_poll = &atmegadci_do_poll, 2154228483Shselasky .set_hw_power_sleep = &atmegadci_set_hw_power_sleep, 2155187160Sthompsa}; 2156