/*      $NetBSD: ohcivar.h,v 1.64 2025/03/31 14:46:42 riastradh Exp $   */

/*
* Copyright (c) 1998 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Lennart Augustsson ([email protected]) at
* Carlstedt Research & Technology.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
*    notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
*    notice, this list of conditions and the following disclaimer in the
*    documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/

#ifndef _OHCIVAR_H_
#define _OHCIVAR_H_

#include <sys/pool.h>

typedef struct ohci_soft_ed {
       ohci_ed_t *ed;
       struct ohci_soft_ed *next;
       ohci_physaddr_t physaddr;
       usb_dma_t dma;
       int offs;
} ohci_soft_ed_t;


typedef struct ohci_soft_td {
       ohci_td_t *td;
       struct ohci_soft_td *nexttd;    /* mirrors nexttd in TD */
       struct ohci_soft_td *dnext;     /* next in done list */
       struct ohci_soft_td **held;     /* where the ref to this std is held */
       ohci_physaddr_t physaddr;
       usb_dma_t dma;
       int offs;
       LIST_ENTRY(ohci_soft_td) hnext; /* next on hash list */
       struct usbd_xfer *xfer;
       uint16_t len;
       uint16_t flags;
#define OHCI_CALL_DONE  0x0001
#define OHCI_ADD_LEN    0x0002
} ohci_soft_td_t;
// #define OHCI_STD_SIZE (roundup(sizeof(struct ohci_soft_td), OHCI_TD_ALIGN))
// #define OHCI_STD_CHUNK 128


typedef struct ohci_soft_itd {
       ohci_itd_t *itd;
       struct ohci_soft_itd *nextitd;  /* mirrors nexttd in ITD */
       struct ohci_soft_itd *dnext;    /* next in done list */
       struct ohci_soft_itd **held;    /* where the ref to this sitd is held */
       ohci_physaddr_t physaddr;
       usb_dma_t dma;
       int offs;
       LIST_ENTRY(ohci_soft_itd) hnext;/* next on hash list */
       struct usbd_xfer *xfer;
       uint16_t flags;
       bool isdone;    /* used only when DIAGNOSTIC is defined */
} ohci_soft_itd_t;
// #define OHCI_SITD_SIZE (roundup(sizeof(struct ohci_soft_itd), OHCI_ITD_ALIGN))
// #define OHCI_SITD_CHUNK 64


#define OHCI_NO_EDS (2*OHCI_NO_INTRS-1)

#define OHCI_HASH_SIZE 128

typedef struct ohci_softc {
       device_t sc_dev;
       struct usbd_bus sc_bus;
       bus_space_tag_t iot;
       bus_space_handle_t ioh;
       bus_size_t sc_size;
       bool sc_attached;

       kmutex_t sc_lock;
       kmutex_t sc_intr_lock;
       void *sc_rhsc_si;

       usb_dma_t sc_hccadma;
       struct ohci_hcca *sc_hcca;
       ohci_soft_ed_t *sc_eds[OHCI_NO_EDS];
       u_int sc_bws[OHCI_NO_INTRS];

       uint32_t sc_eintrs;
       ohci_soft_ed_t *sc_isoc_head;
       ohci_soft_ed_t *sc_ctrl_head;
       ohci_soft_ed_t *sc_bulk_head;

       LIST_HEAD(, ohci_soft_td)  sc_hash_tds[OHCI_HASH_SIZE];
       LIST_HEAD(, ohci_soft_itd) sc_hash_itds[OHCI_HASH_SIZE];

       TAILQ_HEAD(, ohci_xfer) sc_abortingxfers;

       int sc_noport;

       int sc_endian;
#define OHCI_LITTLE_ENDIAN      0       /* typical (uninitialized default) */
#define OHCI_BIG_ENDIAN         1       /* big endian OHCI? never seen it */
#define OHCI_HOST_ENDIAN        2       /* if OHCI always matches CPU */

       int sc_flags;
#define OHCIF_SUPERIO           0x0001

       kcondvar_t sc_abort_cv;

       ohci_soft_ed_t *sc_freeeds;
       ohci_soft_td_t *sc_freetds;
       ohci_soft_itd_t *sc_freeitds;

       pool_cache_t sc_xferpool;       /* free xfer pool */

       struct usbd_xfer *sc_intrxfer;

       uint32_t sc_control;            /* Preserved during suspend/standby */
       uint32_t sc_intre;

       u_int sc_overrun_cnt;
       struct timeval sc_overrun_ntc;

       struct callout sc_tmo_rhsc;
       device_t sc_child;
       char sc_dying;
} ohci_softc_t;

struct ohci_xfer {
       struct usbd_xfer xfer;
       uint32_t ox_abintrs;
       TAILQ_ENTRY(ohci_xfer) ox_abnext;

       /* ctrl */
       ohci_soft_td_t *ox_setup;
       ohci_soft_td_t *ox_stat;
       union {
               /* ctrl/bulk/intr */
               struct {
                       ohci_soft_td_t **ox_stds;
                       size_t ox_nstd;
               };
               /* isoc */
               struct {
                       ohci_soft_itd_t **ox_sitds;
                       size_t ox_nsitd;
               };
       };
};

#define OHCI_BUS2SC(bus)        ((bus)->ub_hcpriv)
#define OHCI_PIPE2SC(pipe)      OHCI_BUS2SC((pipe)->up_dev->ud_bus)
#define OHCI_XFER2SC(xfer)      OHCI_BUS2SC((xfer)->ux_bus)

#define OHCI_XFER2OXFER(xfer)   ((struct ohci_xfer *)(xfer))
#define OHCI_PIPE2OPIPE(pipe)   ((struct ohci_pipe *)(pipe))

int             ohci_init(ohci_softc_t *);
int             ohci_intr(void *);
void            ohci_detach(ohci_softc_t *);
bool            ohci_shutdown(device_t, int);
void            ohci_childdet(device_t, device_t);
int             ohci_activate(device_t, enum devact);
bool            ohci_resume(device_t, const pmf_qual_t *);
bool            ohci_suspend(device_t, const pmf_qual_t *);

#endif /* _OHCIVAR_H_ */