/* usb1401.h
 Header file for the CED 1401 USB device driver for Linux
 Copyright (C) 2010 Cambridge Electronic Design Ltd
 Author Greg P Smith (greg@ced.co.uk)

 This program is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License
 as published by the Free Software Foundation; either version 2
 of the License, or (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/
#ifndef __USB1401_H__
#define __USB1401_H__
#include "use1401.h"
#include "ced_ioctl.h"

#ifndef UINT
#define UINT unsigned int
#endif

/// Device type codes, but these don't need to be extended - a succession is assumed
/// These are set for usb from the bcdDevice field (suitably mangled). Future devices
/// will be added in order of device creation to the list, so the names here are just
/// to help use remember which device is which. The U14ERR_... values follow the same
/// pattern for modern devices.
#define TYPEUNKNOWN        -1             // dont know
#define TYPE1401           0              // standard 1401
#define TYPEPLUS           1              // 1401 plus
#define TYPEU1401          2              // u1401
#define TYPEPOWER          3              // Power1401
#define TYPEU14012         4              // u1401 mkII
#define TYPEPOWER2         5              // Power1401 mk II
#define TYPEMICRO3         6              // Micro1401-3
#define TYPEPOWER3         7              // Power1401-3

/// Some useful defines of constants. DONT FORGET to change the version in the
/// resources whenever you change it here!.
#define DRIVERMAJREV      2             // driver revision level major (match windows)
#define DRIVERMINREV      0             // driver revision level minor

/// Definitions of the various block transfer command codes
#define TM_EXTTOHOST    8               // extended tohost
#define TM_EXTTO1401    9               // extended to1401

/// Definitions of values in usbReqtype. Used in sorting out setup actions
#define H_TO_D 0x00
#define D_TO_H 0x80
#define VENDOR 0x40
#define DEVREQ 0x00
#define INTREQ 0x01
#define ENDREQ 0x02

/// Definition of values in usbRequest, again used to sort out setup
#define GET_STATUS      0x00
#define CLEAR_FEATURE   0x01
#define SET_FEATURE     0x03
#define SET_ADDRESS     0x05
#define GET_DESC        0x06
#define SET_DESC        0x07
#define GET_CONF        0x08
#define SET_CONF        0x09
#define GET_INTERFACE   0x0a
#define SET_INTERFACE   0x0b
#define SYNCH_FRAME     0x0c

/// Definitions of the various debug command codes understood by the 1401. These
/// are used in various vendor-specific commands to achieve the desired effect
#define DB_GRAB         0x50            /* Grab is a NOP for USB */
#define DB_FREE         0x51            /* Free is a NOP for the USB */
#define DB_SETADD       0x52            /* Set debug address (double) */
#define DB_SELFTEST     0x53            /* Start self test */
#define DB_SETMASK      0x54            /* Set enable mask (double) */
#define DB_SETDEF       0x55            /* Set default mask (double) */
#define DB_PEEK         0x56            /* Peek address, save result */
#define DB_POKE         0x57            /* Poke address with data (double) */
#define DB_RAMPD        0x58            /* Ramp data at debug address */
#define DB_RAMPA        0x59            /* Ramp address bus */
#define DB_REPEATS      0x5A            /* Set repeats for operations (double) */
#define DB_WIDTH        0x5B            /* Set width for operations (byte) */
#define DB_DATA         0x5C            /* Get 4-byte data read by PEEK */
#define DB_CHARS        0x5D            /* Send chars via EP0 control write */

#define CR_CHAR          0x0D           /* The carriage return character */
#define CR_CHAR_80       0x8d           /*  and with bit 7 set */

/// A structure holding information about a block of memory for use in circular transfers
typedef struct circBlk
{
    volatile UINT dwOffset;             /* Offset within area of block start */
    volatile UINT dwSize;               /* Size of the block, in bytes (0 = unused) */
} CIRCBLK;

/// A structure holding all of the information about a transfer area - an area of
///  memory set up for use either as a source or destination in DMA transfers.
typedef struct transarea
{
    void*       lpvBuff;                // User address of xfer area saved for completeness
    UINT        dwBaseOffset;           // offset to start of xfer area in first page
    UINT        dwLength;               // Length of xfer area, in bytes
    struct page **pPages;               // Points at array of locked down pages
    int         nPages;                 // number of pages that are locked down
    bool        bUsed;                  // Is this structure in use?
    bool        bCircular;              // Is this area for circular transfers?
    bool        bCircToHost;            // Flag for direction of circular transfer
    bool        bEventToHost;           // Set event on transfer to host?
    int         iWakeUp;                // Set 1 on event, cleared by TestEvent()
    UINT        dwEventSt;              // Defines section within xfer area for...
    UINT        dwEventSz;              // ...notification by the event SZ is 0 if unset
    CIRCBLK     aBlocks[2];             // Info on a pair of circular blocks
    wait_queue_head_t wqEvent;          // The wait queue for events in this area MUST BE LAST
} TRANSAREA;

/// The DMADESC structure is used to hold information on the transfer in progress. It
/// is set up by ReadDMAInfo, using information sent by the 1401 in an escape sequence.
typedef struct dmadesc
{
    unsigned short wTransType;          /* transfer type as TM_xxx above        */
    unsigned short wIdent;              /* identifier word                      */
    unsigned int   dwSize;              /* bytes to transfer                    */
    unsigned int   dwOffset;            /* offset into transfer area for trans  */
    bool           bOutWard;            /* true when data is going TO 1401      */
} DMADESC;

#define INBUF_SZ         256            /* input buffer size */
#define OUTBUF_SZ        256            /* output buffer size */
#define STAGED_SZ 0x10000               // size of coherent buffer for staged transfers

/// Structure to hold all of our device specific stuff. We are making this as similar as we
/// can to the Windows driver to help in our understanding of what is going on.
typedef struct _DEVICE_EXTENSION
{
    char inputBuffer[INBUF_SZ];         /* The two buffers */
    char outputBuffer[OUTBUF_SZ];       /* accessed by the host functions */
    volatile unsigned int dwNumInput;   /* num of chars in input buffer   */
    volatile unsigned int dwInBuffGet;  /* where to get from input buffer */
    volatile unsigned int dwInBuffPut;  /* where to put into input buffer */
    volatile unsigned int dwNumOutput;  /* num of chars in output buffer  */
    volatile unsigned int dwOutBuffGet; /* where to get from output buffer*/
    volatile unsigned int dwOutBuffPut; /* where to put into output buffer*/

    volatile bool bSendCharsPending;    /* Flag to indicate sendchar active */
    volatile bool bReadCharsPending;    /* Flag to indicate a read is primed */
    char* pCoherCharOut;                /* special aligned buffer for chars to 1401 */
    struct urb* pUrbCharOut;            /* urb used for chars to 1401 */
    char* pCoherCharIn;                 /* special aligned buffer for chars to host */
    struct urb* pUrbCharIn;             /* urb used for chars to host */

    spinlock_t charOutLock;             /* to protect the outputBuffer and outputting */
    spinlock_t charInLock;              /* to protect the inputBuffer and char reads */
    __u8 bInterval;                     /* Interrupt end point interval */

    volatile unsigned int dwDMAFlag;    /* state of DMA */
    TRANSAREA rTransDef[MAX_TRANSAREAS];/* transfer area info */
    volatile DMADESC rDMAInfo;          // info on current DMA transfer
    volatile bool bXFerWaiting;         // Flag set if DMA transfer stalled
    volatile bool bInDrawDown;          // Flag that we want to halt transfers

    // Parameters relating to a block read\write that is in progress. Some of these values
    //  are equivalent to values in rDMAInfo. The values here are those in use, while those
    //  in rDMAInfo are those received from the 1401 via an escape sequence. If another
    //  escape sequence arrives before the previous xfer ends, rDMAInfo values are updated while these
    //  are used to finish off the current transfer.
    volatile short StagedId;            // The transfer area id for this transfer
    volatile bool StagedRead;           // Flag TRUE for read from 1401, FALSE for write
    volatile unsigned int StagedLength; // Total length of this transfer
    volatile unsigned int StagedOffset; // Offset within memory area for transfer start
    volatile unsigned int StagedDone;   // Bytes transferred so far
    volatile bool bStagedUrbPending;    // Flag to indicate active
    char* pCoherStagedIO;               // buffer used for block transfers
    struct urb* pStagedUrb;             // The URB to use
    spinlock_t stagedLock;              // protects ReadWriteMem() and circular buffer stuff

    short s1401Type;                    // type of 1401 attached
    short sCurrentState;                // current error state
    bool bIsUSB2;                       // type of the interface we connect to
    bool bForceReset;                   // Flag to make sure we get a real reset
    __u32 statBuf[2];                   // buffer for 1401 state info

    unsigned long ulSelfTestTime;       // used to timeout self test

    int nPipes;                         // Should be 3 or 4 depending on 1401 usb chip
    int bPipeError[4];                  // set non-zero if an error on one of the pipe
    __u8 epAddr[4];                     // addresses of the 3/4 end points

    struct usb_device *udev;            // the usb device for this device
    struct usb_interface *interface;    // the interface for this device, NULL if removed
    struct usb_anchor submitted;        // in case we need to retract our submissions
    struct mutex io_mutex;              // synchronize I/O with disconnect, one user-mode caller at a time

    int    errors;                      // the last request tanked
    int    open_count;                  // count the number of openers
    spinlock_t err_lock;                // lock for errors
    struct kref kref;
}DEVICE_EXTENSION, *PDEVICE_EXTENSION;
#define to_DEVICE_EXTENSION(d) container_of(d, DEVICE_EXTENSION, kref)

/// Definitions of routimes used between compilation object files
// in usb1401.c
extern int Allowi(DEVICE_EXTENSION* pdx);
extern int SendChars(DEVICE_EXTENSION* pdx);
extern void ced_draw_down(DEVICE_EXTENSION *pdx);
extern int ReadWriteMem(DEVICE_EXTENSION *pdx, bool Read, unsigned short wIdent,
                      unsigned int dwOffs, unsigned int dwLen);

// in ced_ioc.c
extern int ClearArea(DEVICE_EXTENSION *pdx, int nArea);
extern int SendString(DEVICE_EXTENSION* pdx, const char __user* pData, unsigned int n);
extern int SendChar(DEVICE_EXTENSION *pdx, char c);
extern int Get1401State(DEVICE_EXTENSION* pdx, __u32* state, __u32* error);
extern int ReadWrite_Cancel(DEVICE_EXTENSION *pdx);
extern bool Is1401(DEVICE_EXTENSION* pdx);
extern bool QuickCheck(DEVICE_EXTENSION* pdx, bool bTestBuff, bool bCanReset);
extern int Reset1401(DEVICE_EXTENSION *pdx);
extern int GetChar(DEVICE_EXTENSION *pdx);
extern int GetString(DEVICE_EXTENSION *pdx, char __user* pUser, int n);
extern int SetTransfer(DEVICE_EXTENSION *pdx, TRANSFERDESC __user *pTD);
extern int UnsetTransfer(DEVICE_EXTENSION *pdx, int nArea);
extern int SetEvent(DEVICE_EXTENSION *pdx, TRANSFEREVENT __user*pTE);
extern int Stat1401(DEVICE_EXTENSION *pdx);
extern int LineCount(DEVICE_EXTENSION *pdx);
extern int GetOutBufSpace(DEVICE_EXTENSION *pdx);
extern int GetTransfer(DEVICE_EXTENSION *pdx, TGET_TX_BLOCK __user *pGTB);
extern int KillIO1401(DEVICE_EXTENSION *pdx);
extern int BlkTransState(DEVICE_EXTENSION *pdx);
extern int StateOf1401(DEVICE_EXTENSION *pdx);
extern int StartSelfTest(DEVICE_EXTENSION *pdx);
extern int CheckSelfTest(DEVICE_EXTENSION *pdx, TGET_SELFTEST __user *pGST);
extern int TypeOf1401(DEVICE_EXTENSION *pdx);
extern int TransferFlags(DEVICE_EXTENSION *pdx);
extern int DbgPeek(DEVICE_EXTENSION *pdx, TDBGBLOCK __user* pDB);
extern int DbgPoke(DEVICE_EXTENSION *pdx, TDBGBLOCK __user *pDB);
extern int DbgRampData(DEVICE_EXTENSION *pdx, TDBGBLOCK __user *pDB);
extern int DbgRampAddr(DEVICE_EXTENSION *pdx, TDBGBLOCK __user *pDB);
extern int DbgGetData(DEVICE_EXTENSION *pdx, TDBGBLOCK __user *pDB);
extern int DbgStopLoop(DEVICE_EXTENSION *pdx);
extern int SetCircular(DEVICE_EXTENSION *pdx, TRANSFERDESC __user *pTD);
extern int GetCircBlock(DEVICE_EXTENSION *pdx, TCIRCBLOCK __user* pCB);
extern int FreeCircBlock(DEVICE_EXTENSION *pdx, TCIRCBLOCK __user* pCB);
extern int WaitEvent(DEVICE_EXTENSION *pdx, int nArea, int msTimeOut);
extern int TestEvent(DEVICE_EXTENSION *pdx, int nArea);
#endif