#ifndef _INC_PMCC4_PRIVATE_H_
#define _INC_PMCC4_PRIVATE_H_

/*-----------------------------------------------------------------------------
 * pmcc4_private.h -
 *
 * Copyright (C) 2005  SBE, Inc.
 *
 *   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.
 */


#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/semaphore.h>
#include <linux/spinlock.h>
#include <linux/interrupt.h>    /* support for tasklets */
#include <linux/timer.h>        /* support for timer */
#include <linux/workqueue.h>
#include <linux/hdlc.h>

#include "libsbew.h"
#include "pmcc4_defs.h"
#include "pmcc4_cpld.h"
#include "musycc.h"
#include "sbe_promformat.h"
#include "comet.h"


/* driver state */
#define SBE_DRVR_INIT        0x0
#define SBE_DRVR_AVAILABLE   0x69734F4E
#define SBE_DRVR_DOWN        0x1

/******************************************************************************
 * MUSYCC Message Descriptor - coupled to hardware implementation, the first
 * three u_int32 must not be reordered.
 */

struct mdesc
{
    volatile u_int32_t status;  /* Buffer Descriptor */
    u_int32_t   data;           /* Data Pointer */
    u_int32_t   next;           /* MUSYCC view of Next Pointer */
    void       *mem_token;      /* Data */
    struct mdesc *snext;
};


/*************************************************************************
 * Private driver data structures, internal use only.
 */

struct c4_chan_info
{
    int         gchan;          /* channel number within group/port 0-31 */
    int         channum;        /* absolute channel number 0-128 */
    u_int8_t    status;
#define TX_RECOVERY_MASK   0x0f
#define TX_ONR_RECOVERY    0x01
#define TX_BUFF_RECOVERY   0x02
#define RX_RECOVERY_MASK   0xf0
#define RX_ONR_RECOVERY    0x10

    unsigned char ch_start_rx;
#define CH_START_RX_NOW    1
#define CH_START_RX_ONR    2
#define CH_START_RX_BUF    3

    unsigned char ch_start_tx;
#define CH_START_TX_1ST    1
#define CH_START_TX_ONR    2
#define CH_START_TX_BUF    3

    char        tx_full;        /* boolean */
    short       txd_free;       /* count of TX Desc available */
    short       txd_required;   /* count of TX Desc needed by mesg */
    unsigned short rxd_num;     /* must support range up to 2000 */
    unsigned short txd_num;     /* must support range up to 1000 */
    int         rxix_irq_srv;

    enum
    {
        UNASSIGNED,             /* AVAILABLE, NOTINUSE */
        DOWN,                   /* ASSIGNED, NOTINUSE */
        UP                      /* ASSIGNED and INUSE */
    }           state;

    struct c4_port_info *up;
    void       *user;

    struct work_struct ch_work;
    struct mdesc *mdt;
    struct mdesc *mdr;
    struct mdesc *txd_irq_srv;
    struct mdesc *txd_usr_add;

#if 0
    /*
     * FUTURE CODE MIGHT SEPARATE TIMESLOT MAP SETUPS INTO SINGLE IOCTL and
     * REMOVE MAPS FROM CHANNEL PARAMETER STRUCTURE
     */
    /*
     * each byte in bitmask below represents one timeslot (bitmask[0] is for
     * timeslot 0 and so on), each bit in the byte selects timeslot bits for
     * this channel (0xff - whole timeslot, 0x7f - 56kbps mode)
     */

    u_int8_t    ts_bitmask[32];
#endif
    spinlock_t  ch_rxlock;
    spinlock_t  ch_txlock;
    atomic_t    tx_pending;

    struct sbecom_chan_stats s;
    struct sbecom_chan_param p;
};
typedef struct c4_chan_info mch_t;

struct c4_port_info
{

    struct musycc_globalr *reg;
    struct musycc_groupr *regram;
    void       *regram_saved;   /* Original malloc value may have non-2KB
                                 * boundary.  Need to save for use when
                                 * freeing. */
    comet_t    *cometbase;
    struct sbe_card_info *up;

    /*
     * The workqueue is used for TX restart of ONR'd channels when in
     * Transparent mode.
     */

    struct workqueue_struct *wq_port;   /* chan restart work queue */
    struct semaphore sr_sem_busy;       /* service request exclusion
                                         * semaphore */
    struct semaphore sr_sem_wait;       /* service request handshake
                                         * semaphore */
    u_int32_t   sr_last;
    short       openchans;
    char        portnum;
    char        group_is_set;   /* GROUP_INIT command issued to MUSYCC,
                                 * otherwise SET_CHAN Ioctl fails */

    mch_t      *chan[MUSYCC_NCHANS];
    struct sbecom_port_param p;

    /*
     * The MUSYCC timeslot mappings are maintained within the driver and are
     * modified and reloaded as each of a group's channels are configured.
     */
    u_int8_t    tsm[32];        /* tsm (time slot map) */
    int         fifomap[32];
};
typedef struct c4_port_info mpi_t;


#define COMET_OFFSET(x) (0x80000+(x)*0x10000)
#define EEPROM_OFFSET   0xC0000
#define ISPLD_OFFSET    0xD0000

/* iSPLD control chip registers */
#define ISPLD_MCSR  0x0
#define ISPLD_MCLK  0x1
#define ISPLD_LEDS  0x2
#define ISPLD_INTR  0x3
#define ISPLD_MAX   0x3

struct sbe_card_info
{
    struct musycc_globalr *reg;
    struct musycc_groupr *regram;
    u_int32_t  *iqd_p;          /* pointer to dword aligned interrupt queue
                                 * descriptors */
    void       *iqd_p_saved;    /* Original malloc value may have non-dword
                                 * aligned boundary.  Need to save for use
                                 * when freeing. */
    unsigned int iqp_headx, iqp_tailx;

    struct semaphore sem_wdbusy;/* watchdog exclusion semaphore */
    struct watchdog wd;         /* statically allocated watchdog structure */
    atomic_t    bh_pending;     /* bh queued, but not yet running */
    u_int32_t   brd_id;         /* unique PCI ID */
    u_int16_t   hdw_bid;      /* on/board hardware ID */
    unsigned short wdcount;
    unsigned char max_port;
    unsigned char brdno;        /* our board number */
    unsigned char wd_notify;
#define WD_NOTIFY_1TX       1
#define WD_NOTIFY_BUF       2
#define WD_NOTIFY_ONR       4
    enum                        /* state as regards interrupt processing */
    {
        C_INIT,                 /* of-board-address not configured or are in
                                 * process of being removed, don't access
                                 * hardware */
        C_IDLE,                 /* off-board-addresses are configured, but
                                 * don't service interrupts, just clear them
                                 * from hardware */
        C_RUNNING               /* life is good, service away */
    }           state;

    struct sbe_card_info *next;
    u_int32_t  *eeprombase;     /* mapped address of board's EEPROM */
    c4cpld_t   *cpldbase;       /* mapped address of board's CPLD hardware */
    char       *release;        /* SBE ID string w/in sbeRelease.c */
    void       *hdw_info;
#ifdef CONFIG_PROC_FS
    struct proc_dir_entry *dir_dev;
#endif

    /* saved off interface assignments which bound a board */
    hdlc_device *first_if;
    hdlc_device *last_if;
    short       first_channum, last_channum;

    struct intlog
    {
        u_int32_t   this_status_new;
        u_int32_t   last_status_new;
        u_int32_t   drvr_intr_thcount;
        u_int32_t   drvr_intr_bhcount;
        u_int32_t   drvr_int_failure;
    }           intlog;

    mpi_t       port[MUSYCC_NPORTS];
    char        devname[SBE_IFACETMPL_SIZE + 1];
    atomic_t    tx_pending;
    u_int32_t   alarmed[4];     /* dpm211 */

#if defined(SBE_ISR_TASKLET)
    struct tasklet_struct ci_musycc_isr_tasklet;
#elif defined(SBE_ISR_IMMEDIATE)
    struct tq_struct ci_musycc_isr_tq;
#endif
};
typedef struct sbe_card_info ci_t;

struct s_hdw_info
{
    u_int8_t    pci_busno;
    u_int8_t    pci_slot;
    u_int8_t    pci_pin[2];
    u_int8_t    revid[2];
    u_int8_t    mfg_info_sts;
#define EEPROM_OK          0x00
#define EEPROM_CRCERR      0x01
    char        promfmt;        /* prom type, from sbe_promformat.h */

    char        devname[SBE_IFACETMPL_SIZE];
    struct pci_bus *bus;
    struct net_device *ndev;
    struct pci_dev *pdev[2];

    unsigned long addr[2];
    unsigned long addr_mapped[2];
    unsigned long len[2];

    union
    {
        char        data[128];
        FLD_TYPE1   pft1;       /* prom field, type #1 */
        FLD_TYPE2   pft2;       /* prom field, type #2 */
    }           mfg_info;
};
typedef struct s_hdw_info hdw_info_t;

/*****************************************************************/

struct c4_priv
{
    int         channum;
    struct sbe_card_info *ci;
};


/*****************************************************************/

extern ci_t *c4_list;

mch_t      *c4_find_chan (int);
int         c4_set_chan (int channum, struct sbecom_chan_param *);
int         c4_get_chan (int channum, struct sbecom_chan_param *);
int         c4_get_chan_stats (int channum, struct sbecom_chan_stats *);

#endif                          /* _INC_PMCC4_PRIVATE_H_ */