cy7c67200_300_lcd.c

来自「linux嵌入式课程实践中的一个关于声卡驱动程序 。」· C语言 代码 · 共 2,069 行 · 第 1/5 页

C
2,069
字号
/* cy7c67200_300_lcd.c *//******************************************************************* * *    DESCRIPTION: *   The Low-level Controller Driver (LCD) contains generic routines *   to help handle the OTG protocols and to communicate with the *   CY7C67200/300 ASIC.  "Helper" functions are provided to for data *   transfer from the HCD's/PCD's to the Lyberty ASIC * *    HISTORY: * *  Copyright (c) Cypress Semiconductor 2002 * *******************************************************************//** include files **/#include <linux/slab.h>#include <asm/io.h>#include <stdio.h>#include "cy7c67200_300_otg.h"#include "cy7c67200_300_lcd.h"#include <linux/usb.h>#include "cy7c67200_300_hcd.h"#include "cy7c67200_300_debug.h"#include "usbd/bi/cy7c67200_300_pcd.h"#include "67300.h"#include "hwfixes.h"#include "lcp_cmd.h"#include "lcp_data.h"/** local definitions **/#define HPI_STAT_ADDR    (HPI_STAT_PORT << 8)#define HPI_MBX_ADDR     (HPI_MBX_PORT << 8)#define HPI_DATA_ADDR    (HPI_DATA_PORT << 8)#define HPI_ADDR_ADDR    (HPI_ADDR_PORT << 8)/** default settings **//** external functions **//** external data **/int cy_dbg_on = 0;/** internal functions **/static int lcd_writeable_region(unsigned short chip_addr, int byte_length);static int lcd_start_lcp(lcd_lcp_entry_t * lcp, cy_priv_t * cy_private_data);static lcd_lcp_entry_t * lcd_create_lcp_entry(unsigned short command,         unsigned short arg1, unsigned short arg2, unsigned short arg3,         unsigned short arg4, unsigned short arg5, unsigned short arg6,         unsigned short arg7, unsigned short arg8, unsigned short arg9,         unsigned short arg10, unsigned short arg11, unsigned short arg12,         unsigned short arg13, unsigned short arg14, unsigned short arg15,         char * buf, int len, lcd_callback_t funcptr, int opt_arg,         cy_priv_t * priv_data);static int lcd_add_lcp_entry(lcd_lcp_entry_t * lcp, cy_priv_t *                              cy_private_data);static unsigned short lcd_get_ushort(char * data, int start_address);static void lcp_handle_mailbox(cy_priv_t * cy_private_data);/** public data **//** private data **//** public functions **//* *  FUNCTION: lcd_get_cb_address * *  PARAMETERS: *    port_num              - Port number *    endpoint              - Endpoint number *    cy_private_data       - Private data structure pointer * *  DESCRIPTION: *    This function returns the callback address for the specified *    port number and endpoint. * *  RETURNS:  *      NULL    - Enpoint number invalid *      address - Callback address for specified port number and endpoint *    */unsigned short lcd_get_cb_address(unsigned short port_num,                                  int endpoint,                                  cy_priv_t * cy_private_data){    unsigned short cb_address = 0x0;    lcd_priv_data_t *  lcd_private_data =         (lcd_priv_data_t *) cy_private_data->lcd_priv;    if ((endpoint >= 0) && (endpoint < MAX_NUM_ENDPOINTS)) {        if ((port_num == PORT0) || port_num == PORT1) {            cb_address = lcd_private_data->sie1_cb_addresses[endpoint];        } else {            cb_address = lcd_private_data->sie2_cb_addresses[endpoint];        }    }    return cb_address;}/* *  FUNCTION: lcd_load_ibios * *  PARAMETERS: *    cy_private_data - Private data structure pointer * *  DESCRIPTION: *    This function copies an image of BIOS for internal RAM to RAM and  *    executes the new BIOS. * *    If there is not a BIOS image to download, then the size of ibios should *    be zero in length. * *  RETURNS:  *    SUCCESS         - Success *    Error           - Failure */#ifdef LOAD_IBIOS#include "ibios.h"#elsestatic unsigned char ibios[0];#endifint lcd_load_ibios(cy_priv_t * cy_priv){    int response;    unsigned short address;    int download_length;    char *download_data;    if( sizeof(ibios) == 0 )    {        unsigned short intStat;        cy_err("Skipping IBIOS download");        lcd_hpi_read_mbx(cy_priv);        lcd_hpi_read_status_reg(cy_priv);        // Had to add the write due to a bug in BIOS where they overwrite        // the mailbox after initialization with garbage.  The read clears        // any pending interrupts.        lcd_write_reg (HPI_SIE1_MSG_ADR, 0, cy_priv);        lcd_read_reg (HPI_SIE1_MSG_ADR, &intStat, cy_priv);        lcd_write_reg (HPI_SIE2_MSG_ADR, 0, cy_priv);        lcd_read_reg (HPI_SIE2_MSG_ADR, &intStat, cy_priv);        lcd_write_reg (HOST1_STAT_REG, 0xFFFF, cy_priv);        lcd_write_reg (HOST2_STAT_REG, 0xFFFF, cy_priv);        lcd_write_reg( HPI_SIE_IE, SOFEOP1_TO_HPI_EN | SOFEOP1_TO_CPU_EN |                       RESUME1_TO_HPI_EN | VBUS_TO_HPI_EN | ID_TO_HPI_EN |                       SIE1MSG_TO_HPI_EN, cy_priv );        lcd_read_reg (SIE1_INT_EN_REG, &intStat, cy_priv);        intStat |= VBUS_IRQ_EN | ID_IRQ_EN;        lcd_write_reg(SIE1_INT_EN_REG, intStat, cy_priv);        return SUCCESS;    }    if( lcd_get_ushort(ibios, 0x00) != 0xc3b6 )    {        return ERROR;    }    address = lcd_get_ushort(ibios, 0x0e);    download_length = lcd_get_ushort(ibios, 0x0b);    download_data = &ibios[16];    cy_dbg("loading ibios, addr: 0x%04x, length 0x%04x",            address, download_length);    response = lcd_download_code(address, download_length, download_data, 0, 0,                                 cy_priv);    if( response == ERROR )    {        cy_err("lcd_load_ibios: download error\n");    }    else    {        unsigned short intStat;        mdelay(500);        lcd_hpi_read_mbx(cy_priv);        lcd_hpi_read_status_reg(cy_priv);        // Had to add the write due to a bug in BIOS where they overwrite        // the mailbox after initialization with garbage.  The read clears        // any pending interrupts.        lcd_write_reg (HPI_SIE1_MSG_ADR, 0, cy_priv);        lcd_read_reg (HPI_SIE1_MSG_ADR, &intStat, cy_priv);        lcd_write_reg (HPI_SIE2_MSG_ADR, 0, cy_priv);        lcd_read_reg (HPI_SIE2_MSG_ADR, &intStat, cy_priv);        lcd_write_reg (HOST1_STAT_REG, 0xFFFF, cy_priv);        lcd_write_reg (HOST2_STAT_REG, 0xFFFF, cy_priv);        lcd_write_reg( HPI_SIE_IE, SOFEOP1_TO_HPI_EN | SOFEOP1_TO_CPU_EN |                       RESUME1_TO_HPI_EN | VBUS_TO_HPI_EN | ID_TO_HPI_EN |                       SIE1MSG_TO_HPI_EN, cy_priv );        lcd_read_reg (SIE1_INT_EN_REG, &intStat, cy_priv);        intStat |= VBUS_IRQ_EN | ID_IRQ_EN;        lcd_write_reg(SIE1_INT_EN_REG, intStat, cy_priv);        // Move buffer area around ibios        // Would use length, but ibios has a data area at the end        cy_priv->cy_buf_addr = 0x2100;    }    return response;}/* *  FUNCTION: lcd_init * *  PARAMETERS: *    download_filename_ptr - Download filename/path null terminated string *    cy_private_data       - Private data structure pointer * *  DESCRIPTION: *    This function initializes the LCD private data structure, the LCP entry *    list and downloads code to the ASIC. * *  RETURNS:  *    SUCCESS         - Success *    ERROR           - Failure */int lcd_init(char * download_data,             int download_length,             lcd_callback_t funcptr,             int opt_arg,             cy_priv_t * cy_private_data){    lcd_priv_data_t * lcd_private_data = NULL;    int response = ERROR;    unsigned short address;    /* Initialize private data */    if (cy_private_data != NULL) {        cy_private_data->lcd_priv = kmalloc(sizeof(lcd_priv_data_t), 0);                if (cy_private_data->lcd_priv != NULL) {            /* point to lcd private data */            lcd_private_data = (lcd_priv_data_t *) cy_private_data->lcd_priv;            /* Initialize LCP List */            INIT_LIST_HEAD(&lcd_private_data->lcd_lcp_list);            /* Initialize to unlocked state */            lcd_private_data->lcd_lock = SPIN_LOCK_UNLOCKED;                        response = lcd_load_ibios(cy_private_data);            /* do it again in case we loaded bios */            INIT_LIST_HEAD(&lcd_private_data->lcd_lcp_list);            /* Download Lyberty RAM Code */            if ((download_data != NULL) && (download_length > 0)) {                /* Org address */                address = lcd_get_ushort(download_data, 0xe);                download_length = lcd_get_ushort(download_data, 0xb) - 2;                if ((response = lcd_download_code(address, download_length,                                       &download_data[16], funcptr,                                      opt_arg, cy_private_data)) == ERROR) {                    cy_err("lcd_init: download error\n");                }                if( response != ERROR )                {                    cy_private_data->cy_buf_addr = address + download_length;                    // Word align address                    if( (cy_private_data->cy_buf_addr & 1) != 0 )                    {                        cy_private_data->cy_buf_addr += 1;                    }                }            }             else {                response = SUCCESS;            }        }        else            cy_err("lcd_init: kmalloc error\n");    }    else        cy_err("lcd_init: Invalid cy_priv_t pointer\n");    if( response == SUCCESS )    {        enable_irq(cy_private_data->cy_irq);    }    return response;}/* *  FUNCTION: lcd_complete_lcp_entry * *  PARAMETERS: *    cy_private_data - Private data structure pointer * *  DESCRIPTION: *    This function "completes" the first LCP entry by calling the "Callback" *    function (if any) and then deleting the entry from the list.  The function can *    be called from both a "task" and "interrupt" context. * *  RETURNS:  *    SUCCESS         - Success *    Error           - Failure */int lcd_complete_lcp_entry(cy_priv_t * cy_private_data){    lcd_priv_data_t * lcd_private_data =         (lcd_priv_data_t *) cy_private_data->lcd_priv;    lcd_lcp_entry_t * lcp;    int response = ERROR;    int lock_flags;    if (!list_empty(&lcd_private_data->lcd_lcp_list)) {        /* Get LCP entry */        lcp = list_entry(lcd_private_data->lcd_lcp_list.next,                          lcd_lcp_entry_t, list);        /* Call callback (if necessary) */        if (lcp->funcptr != NULL)            lcp->funcptr(lcp->response, lcp->value, lcp->opt_arg,                          lcp->cy_priv_data);        /* Do not allow interrupts and etc. */        spin_lock_irqsave(&lcd_private_data->lcd_lock, lock_flags);        /* Remove entry from linked list */        list_del(lcd_private_data->lcd_lcp_list.next);        /* allow interrupts and etc. */        spin_unlock_irqrestore(&lcd_private_data->lcd_lock, lock_flags);        /* Free memory */        kfree(lcp);        /* Indicate success */        response = SUCCESS;        /* Start up next "valid" LCP entry */        while (!list_empty(&lcd_private_data->lcd_lcp_list)) {            /* Get LCP entry */            lcp = list_entry(lcd_private_data->lcd_lcp_list.next,                              lcd_lcp_entry_t, list);            if (lcd_start_lcp(lcp, cy_private_data) == SUCCESS) {                /* LCP entry successfully started */                break;            }            else {                /* Do not allow interrupts and etc. */                spin_lock_irqsave(&lcd_private_data->lcd_lock, lock_flags);                /* Remove "BAD" LCP entry and try again */                list_del(lcd_private_data->lcd_lcp_list.next);                            /* allow interrupts and etc. */                spin_unlock_irqrestore(&lcd_private_data->lcd_lock, lock_flags);                /* Free memory */                kfree(lcp);            }        }    }    else        cy_err("lcd_complete_lcp_entry: No LCP entry to complete\n");    return(response);}/* *  FUNCTION: lcd_command * *  PARAMETERS: *    command         - Command to perform *    command_arg     - Command argument *    chip_addr       - Offset Address of the ASIC *    port_number     - ASIC Port number  *    funcptr         - Function (Callback) to call when command completes *                      (If not an immediate command)

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?