/**
 * @file daic_hw.h
 *
 * Daic-Hardware - Module for direct hardware communication with the board.
 *
 * Copyright: 2003 Thomas Wintergerst. All rights reserved.
 *
 * $FreeBSD$
 * $Id: daic_hw.h,v 1.1.2.1 2006/02/28 21:35:13 thomas Exp $
 * $Project:    CAPI for BSD $
 * $Target:     daic - CAPI manager driver for Diehl active ISDN controllers $
 * @date        02.02.2003
 * @author      "Thomas Wintergerst" <twinterg@gmx.de>
 * <p>
 *
 * 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 AUTHOR 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 AUTHOR 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.
 *
 * </p>
 */

#ifndef __DAIC_HW_H
#define __DAIC_HW_H

#include <c4b/daic/daic_var.h>
#include <c4b/daic/daic_hwdefs.h>
#include <c4b/daic/daic_board_params.h>





/* === Public declarations =============================================== */





/* --- data structures for handling requests, return codes and indications --- */

/** Magical value to mark a notification mbuf as a return code structure. */
#define DAIC_MBUF_MAGIC_RC      0x01

/** Magical value to mark a notification mbuf as an indication structure. */
#define DAIC_MBUF_MAGIC_IND     0x02

/**
 * This data structure will be used to store request data in the request queue
 * of a port through an mbuf. 
 *
 * The data portion may or may not be filled. This depends on the request value.
 * The data buffer can use up any size from 0 to 270 bytes. The last  16bit
 * word of the structure determines the number of following bytes. If there is
 * no data for this indication, the length word will be zero.
 *
 * The data block is made variable, because of the regular mbuf size. As an mbuf
 * has a size of 256 bytes including any header data, the maximum length of a
 * request data buffer of 270 bytes including this structure would need an mbuf
 * cluster, thus wasting precious space.
 *
 * If the request is an Assign-Request, the member bAssignReqQualification tells
 * the purpose of this request (one of the values DAIC_ID_QUALIFY_*). It can
 * originate from the global id engine (to listen for incoming calls) or a PLCI
 * state machine. For the later the PLCI number is also specified, so the
 * corresponding return code can be dispatched to the origination of the
 * request.
 *
 * Another special use are [U|E]Data-Requests. The data block to send for these
 * messages is not copied to the memory following this structure. Instead the
 * data block is attached as a second mbuf to the mbuf containing this
 * structure. Therefore it is not necessary to copy the data block in pieces
 * from its originating mbuf to several new mbufs (for MData-Requests and the
 * final [U|E]Data-Request) and finally a second time to the controller shared
 * memory. The member wDataLength must be set to null when creating the
 * controller message. This field is later used as the index of the next portion
 * of data to send to the controller.
 */
typedef struct
{
   u_int8_t  bReq;
   u_int8_t  bReqId;
   u_int8_t  bReqCh;
   u_int8_t  bAssignReqQualification;
   u_int16_t wAssignReqPlci;
   u_int16_t wDataLength;
   /* There might be up to 270 bytes following, the number is stored in
    * wDataLength
    */
} DaicReqData_t;

/**
 * This data structure will be created by the interrupt handler when a return
 * code is reported. All data necessary to handle the return code will be stored
 * into this structure, that is itself stored into an mbuf and transfered to the
 * CAPI manager. The CAPI manager will return this mbuf out of interrupt context
 * to this driver.
 *
 * If the corresponding request was a [B|E|U]Data-Request, the field
 * bReqSuppressed is set to a value other than null, if sending the data block
 * was suppressed and will not complete any more. This can happen when a
 * NL-Disconnect-Indication is received while sending a data block is pending.
 * The NCCI then must not expect more return codes to arrive (a data block may
 * be sent in several portions with a return code sent for each portion), but
 * this will be the last return code.
 *
 * If the corresponding request was an Assign-Request, the member
 * bAssignReqQualification will be set to the value of the corresponding
 * Assign-Request (one of DAIC_ID_QUALIFY_*).
 */
typedef struct
{
   u_int8_t  bMagic;            /**< Must be DAIC_MBUF_MAGIC_RC. */
   u_int8_t  bRc;
   u_int8_t  bRcId;
   u_int8_t  bRcCh;
   u_int8_t  bReqSuppressed;
   u_int8_t  bAssignReqQualification;
   u_int16_t wAssignReqPlci;
} DaicRcData_t;

/**
 * This data structure will be created by the interrupt handler when an
 * indication is signalled by the board. All data from the indication is fetched
 * from the board and filled into the data structure, which itself is stored
 * into an mbuf and transfered to the CAPI manager. The CAPI manager will return
 * this mbuf out of interrupt context to this driver.
 *
 * The data portion may or may not be filled. This depends on the indication
 * value. The data buffer can use up any size from 2 to 272 bytes. The first
 * 16bit word (translated machine byte order) determines the number of following
 * bytes. If there is no data for this indication, the length word will be zero.
 *
 * The data block is made variable, because of the regular mbuf size. As an mbuf
 * has a size of 256 bytes including any header data, the maximum length of an
 * indication data buffer of 272 bytes including the length word would need an
 * mbuf cluster, thus wasting precious space.
 */
typedef struct
{
   u_int8_t  bMagic;            /**< Must be DAIC_MBUF_MAGIC_IND. */
   u_int8_t  bInd;
   u_int8_t  bIndId;
   u_int8_t  bIndCh;
   u_int8_t  bMInd;
   u_int8_t  bFill;             /**< Fill byte for alignment. */
   u_int16_t wMLength;
   u_int16_t wDataLength;
   /* There might be up to 270 bytes following, the number is stored in
    * wDataLength
    */
} DaicIndData_t;





/* === Prototypes of interface functions ================================= */





/**
 * Perform a reset operation on a controller.
 */
extern void daichw_reset
   (DaicSc_t *pSc);

/**
 * Check if a board has a primary or basic rate interface.
 *
 * This function does some write operations behind the memory range of the S0
 * boards (also true for quadro boards). If it succeeds this must be a primary
 * board, else an S0 board (single or quadro).
 *
 * @param pSc                   I/O: Softc structure for the board device.
 *
 * @retval 1                    The board was identified as an S2m board.
 * @retval 0                    The board is one of the S0 boards.
 */
extern int daichw_check_for_primary
   (DaicSc_t *pSc);

/**
 * Check for valid memory base address assignment for the board type.
 *
 * The valid memory base address varies between the different board types. For S
 * and Sx addresses from 0xC0000 to 0xDE000 are valid, all on a 8KB boundary.
 * For the other boards addresses from 0x80000 to 0xFE800 are valid, they must
 * be on a 2KB boundary.
 *
 * If this function is called with a (yet) unknown board type, the ckeck will
 * succeed for any allowed value for any board type.
 *
 * @param pSc                   I: The device softc structure.
 * @param ulMemBase             I: The memory base address to check for validity.
 *
 * @retval 1                    The irq number specified is valid for the card
 *                              type stored in the structure pointed to by pSc.
 * @retval 0                    The irq number specified is not valid for the
 *                              card type stored in the structure pointed to by
 *                              pSc.
 */
extern int daichw_check_for_valid_membase
   (DaicSc_t      *pSc,
    unsigned long  ulMemBase);

/**
 * Check for valid irq assignment for the board type.
 *
 * For the boards S and Sx the interrupts 2, 3, 4, 10, 11 and 12 are valid. All
 * others accept also interrupts 5 and 7. If this function is called with an
 * unknown board type, it will succeed with any interrupt valid for any board
 * type.
 *
 * @param pSc                   I: The device softc structure.
 * @param iIrq                  I: The irq number to check for validity.
 *
 * @retval 1                    The irq number specified is valid for the card
 *                              type stored in the structure pointed to by pSc.
 * @retval 0                    The irq number specified is not valid for the
 *                              card type stored in the structure pointed to by
 *                              pSc.
 */
extern int daichw_check_for_valid_irq
   (DaicSc_t *pSc,
    int       iIrq);

/**
 * Download the bootstrap code and identify the board type.
 *
 * This function is called during device probing to identify the real board
 * type. Therefore the primary bootstrap has to be loaded onto the board. The
 * bootcode will then identify the hardware and perform a memory check. When the
 * board is later downloaded with its protocol firmware, there is no need to
 * identify the board or to perform an additional memory check.
 *
 * @param pSc                   I/O: The device softc structure.
 * @param pabBootCode           I: The bootstrap code to download, must be
 *                                 exactly 1K large.
 *
 * @retval 0                    Bootstrapping and board identification was
 *                              successful.
 * @retval Else                 Errno value as an error result.
 */
extern int daichw_bootload_and_identify
   (DaicSc_t *pSc,
    u_int8_t *pabBootCode);

/**
 * Download the bootstrap code to the board without identifying it.
 *
 * This function is called when the user requests a download operation. At this
 * point the board is already identified and it has passed its memory check. So
 * during this operation the user _may_ only decide to do another memory check.
 * The normal operation would be not to do this.
 *
 * @param pSc                   I/O: The device softc structure.
 * @param pabBootCode           I: The bootstrap code to download, must be
 *                                 exactly 1K large.
 * @param fDoMemCheck           I:
 *                              - 0: No memory check is performed after the
 *                                 download operation.
 *                              - Else: After the download the board shall
 *                                 execute a check on its on-board memory.
 *
 * @retval 0                    Bootstrapping and board identification was
 *                              successful.
 * @retval Else                 Errno value as an error result.
 */
extern int daichw_bootload
   (DaicSc_t *pSc,
    u_int8_t *pabBootCode,
    int       fDoMemCheck);

/**
 * Download the protocol firmware to the board including the protocol
 * configuration.
 *
 * @param pSc                   I/O: The device softc structure.
 * @param pabFirmware           I: The firmware code to download. The length of
 *                                 this data block is in nLenFirmware.
 * @param nLenFirmware          I: The length of the firmware code block at
 *                                 pabFirmware.
 * @param pConfig               I: The address of the board configuration data.
 *                                 This parameter is optional and maybe NULL.
 *
 * @retval 0                    The firmware download operation was successful.
 * @retval Else                 Errno value as an error result.
 */
extern int daichw_load_firmware
   (DaicSc_t                    *pSc,
    const u_int8_t              *pabFirmware,
    size_t                       nLenFirmware,
    const DaicBoardConfigData_t *pConfig);

/**
 * Interrupt handler routine for daic devices.
 */
extern void daichw_intr
   (DaicSc_t *pSc);

/**
 * Try to send the next request pending in the request queue.
 *
 * This function will check if there is at least one request pending in the
 * request queue for the controller specified through its port data pointer. If
 * there is no request, nothing is done.
 *
 * If the queue is not empty, the function first checks if the port may accept
 * another request. If this is the case, the request is sent to the board and
 * the corresponding queue entry is released.
 *
 * Else we must ensure that the board will tell us when it is ready to receive
 * another request. This can be done by forcing the board to raise a ready
 * interrupt. But if there is already a ready interrupt pending, we do not need
 * to do anything now. We just wait for this pending interrupt.
 *
 * @attention This function must be called with C4B privilege level or within
 *            interrupt context.
 *
 * @param pSc                   I/O: The device softc structure.
 * @param pPortData             I/O: The port for the desired operation.
 *
 * @return Nothing.
 */
extern void daichw_rq_handle_next
   (DaicSc_t       *pSc,
    DaicPortData_t *pPortData);





#endif /* __DAIC_HW_H */
