⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tc86c001.c

📁 Linux2.4.20针对三星公司的s3c2440内核基础上的一些设备驱动代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * linux/drivers/usbd/bi/tc86c001.c -- USB Device Controller driver.  * * Copyright (c) 2000, 2001, 2002 Lineo * * By:  *      Stuart Lynne <sl@lineo.com>,  *      Tom Rushworth <tbr@lineo.com>,  *      Bruce Balden <balden@lineo.com> * * Copyright (C) 2002 Toshiba Corporation * * 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., 675 Mass Ave, Cambridge, MA 02139, USA. * *//***************************************************************************/#include <linux/config.h>#include <linux/module.h>#include "../usbd-export.h"#include "../usbd-build.h"#include "../usbd-module.h"MODULE_AUTHOR ("sl@lineo.com, tbr@lineo.com, TOSHIBA Corporation");MODULE_LICENSE("GPL");MODULE_DESCRIPTION ("USB Device TC86C001 Bus Interface");USBD_MODULE_INFO ("tc86c001_bi 0.1-alpha");#include <linux/kernel.h>#include <linux/slab.h>#include <linux/interrupt.h>#include <linux/pci.h>#include <linux/init.h>#include <asm/atomic.h>#include <asm/io.h>#include <linux/netdevice.h>#include <asm/irq.h>#include <asm/system.h>#include <asm/types.h>#include <asm/uaccess.h>#include <asm/io.h>#include <linux/delay.h>#include "../usbd.h"#include "../usbd-debug.h"#include "../usbd-func.h"#include "../usbd-bus.h"#include "../usbd-inline.h"#include "usbd-bi.h"#define EP0_PACKETSIZE  0x8#define UDC_MAX_ENDPOINTS       4#define UDC_NAME        "TC86C001 USBD"/* offset 0x000-0x1ff */struct tc_udc_regs{    volatile u32 IntStatus;    volatile u32 IntEnable;    volatile u32 MstSetting;    volatile u32 MstWrStart;    volatile u32 MstWrEnd;        /* 0x010 */    volatile u32 MstWrCurr;    volatile u32 MstRdStart;    volatile u32 MstRdEnd;    volatile u32 MstRdCurr;        /* 0x020 */    volatile u32 PowerDetect;};/* offset 0x200-0x7ff */struct tc_udc_udcregs{    volatile u32 EPxFIFO[8];        /* 0x00 */    volatile u32 EPxMode[8];        /* 0x20 (0:reserved) */    volatile u32 EPxStatus[8];        /* 0x40 */    volatile u32 EPxSizeLA[8];        /* 0x60 */    volatile u32 EPxSizeLB[8];        /* 0x80 (0:reserved) */    volatile u32 EPxSizeHA[8];        /* 0xa0 (0:reserved) */    volatile u32 EPxSizeHB[8];        /* 0xc0 (0:reserved) */    volatile u32 unused1[8];    volatile u32 bmReqType;        /* 0x100 */    volatile u32 bRequest;    volatile u32 wValueL;    volatile u32 wValueH;    volatile u32 wIndexL;    volatile u32 wIndexH;    volatile u32 wLengthL;    volatile u32 wLengthH;    volatile u32 SetupRecv;        /* 0x120 */    volatile u32 CurrConfig;    volatile u32 StdRequest;    volatile u32 Request;    volatile u32 DataSet[2];    volatile u32 UsbState;    volatile u32 EOP;    volatile u32 Command;        /* 0x140 */    volatile u32 EPxSingle[2];    volatile u32 EPxBCS[2];    volatile u32 unused2;    volatile u32 IntControl;    volatile u32 unused3;    volatile u32 StdReqMode;        /* 0x160 */    volatile u32 ReqMode;    volatile u32 unused4[6];    volatile u32 PortStatus;        /* 0x180 */    volatile u32 unused5[2];    volatile u32 Address;    volatile u32 BuffTest;    volatile u32 unused6;    volatile u32 UsbReady;    volatile u32 unused7;    volatile u32 SetDescStall;        /* 0x1a0 */};/* MstSetting.MST_connection == 0 */#define UDC_MSTWR_ENDPOINT        1#define UDC_MSTRD_ENDPOINT        2#define UDC_DESCRAM_SIZE        0x80/* offset 0x800-0x9ff */struct tc_udc_ramregs{    volatile u32 DescRam[UDC_DESCRAM_SIZE];};/* IntStatus/IntEnable */#define INT_SUSPEND        0x00001#define INT_USBRESET        0x00002#define INT_ENDPOINT0        0x00004#define INT_SETUP        0x00008#define INT_STATUS        0x00010#define INT_STATUSNAK        0x00020#define INT_EP1DATASET        0x00040#define INT_EP2DATASET        0x00080#define INT_EP3DATASET        0x00100#define INT_EPxDATASET(n)        (0x00040 << ((n) - 1))#define INT_EP1NAK        0x00200#define INT_EP2NAK        0x00400#define INT_EP3NAK        0x00800#define INT_EPnNAK(n)        (0x00200 < ((n) - 1))#define INT_SOF        0x01000#define INT_ERR        0x02000#define INT_MSTWRSET        0x04000#define INT_MSTWREND        0x08000#define INT_MSTWRTMOUT        0x10000#define INT_MSTRDEND        0x20000#define INT_SYSERROR        0x40000#define INT_PWRDETECT        0x80000/* MstSetting */#define MST_EOPB_DIS        0x0800#define MST_EOPB_ENA        0x0400#define MST_TIMEOUT_DIS        0x0200#define MST_TIMEOUT_ENA        0x0100#define MST_RD_EOPB        0x0080#define MST_RD_RESET        0x0040#define MST_WR_RESET        0x0020#define MST_RD_ENA        0x0004        /* 1:start, 0:ignore */#define MST_WR_ENA        0x0002        /* 1:start, 0:ignore */#define MST_CONNECTION        0x0001#define MST_RW_BITS        0x0f67        /* read/write bits *//* PowerDetect */#define PW_DETECT        0x04#define PW_RESETB        0x02#define PW_PLLUPENB        0x01/* udcregs StdRequest/StdReqMode */#define STDREQ_S_INTERFACE        0x80#define STDREQ_G_INTERFACE        0x40#define STDREQ_S_CONFIG                0x20#define STDREQ_G_CONFIG                0x10#define STDREQ_G_DESCRIPT        0x08#define STDREQ_S_FEATURE        0x04#define STDREQ_C_FEATURE        0x02#define STDREQ_G_STATUS                0x01/* udcregs EPxStatus */#define EPxSTATUS_TOGGLE        0x40#define EPxSTATUS_SUSPEND        0x20#define EPxSTATUS_EP_MASK        0x1c#define EPxSTATUS_EP_READY        0x00#define EPxSTATUS_EP_DATAIN        0x04#define EPxSTATUS_EP_FULL        0x08#define EPxSTATUS_EP_TX_ERR        0x0c#define EPxSTATUS_EP_RX_ERR        0x10#define EPxSTATUS_EP_BUSY        0x14#define EPxSTATUS_EP_STALL        0x18#define EPxSTATUS_EP_INVALID        0x1c#define EPxSTATUS_FIFO_DISABLE        0x02#define EPxSTATUS_STAGE_ERROR        0x01/* udcregs Command */#define COMMAND_SETDATA0        2#define COMMAND_RESET        3#define COMMAND_STALL        4#define COMMAND_INVALID        5#define COMMAND_EP(n)        ((n) << 4)/* udcregs UsbState */#define USBSTATE_CONFIGURED        0x04#define USBSTATE_ADDRESSED        0x02#define USBSTATE_DEFAULT        0x01static struct pci_dev *udc_pci_dev;        /* only one instance */static struct tc_udc_regs *tc_regs;static struct tc_udc_udcregs *tc_udcregs;static struct tc_udc_ramregs *tc_ramregs;static struct usb_device_instance *udc_device;        // required for the interrupt handler/* * ep_endpoints - map physical endpoints to logical endpoints */static struct usb_endpoint_instance *ep_endpoints[UDC_MAX_ENDPOINTS];static dma_addr_t ep_dmaaddrs[UDC_MAX_ENDPOINTS];static struct urb *ep0_urb;extern unsigned int udc_interrupts;static int nodma;MODULE_PARM (nodma, "i");MODULE_PARM_DESC (nodma, "Disable DMA");/* *********************************************************************** *//* IO *//** * tc_write_buffer - write a buffer to the tc fifo * @ep: endpoint * @b: pointer to buffer to write * @size: number of bytes to write */static voidtc_write_buffer (unsigned char ep, unsigned char *b, unsigned char size){    while (size--) {        writel (*b++, &tc_udcregs->EPxFIFO[ep]);    }}/** * tc_read_buffer - fill a buffer from the tc fifo * @ep: endpoint * @b: pointer to buffer to fill * @size: number of bytes to read */static voidtc_read_buffer (unsigned char ep, unsigned char *b, unsigned char size){    while (size--) {        *b++ = readl (&tc_udcregs->EPxFIFO[ep]);    }}/** * tc_read_epxsize - read data count in FIFO of the endpoint. * @ep: endpoint */static inttc_read_epxsize (unsigned int ep){    int low = readl (&tc_udcregs->EPxSizeLA[ep]);    int size;    /* SizeH: DATA[9:7], SizeH: DATA[6:0] */    if (low & 0x80) {        size = ((readl (&tc_udcregs->EPxSizeHA[ep]) & 0x03) << 7) |            (low & 0x7f);    } else {        low = readl (&tc_udcregs->EPxSizeLB[ep]);        size = ((readl (&tc_udcregs->EPxSizeHB[ep]) & 0x03) << 7) |            (low & 0x7f);    }    return size;}static voidcopy_descram (const void *data, int len, int *ofs){    const unsigned char *p = (const unsigned char *) data;    int i;    if (*ofs <= UDC_DESCRAM_SIZE && *ofs + len > UDC_DESCRAM_SIZE)        printk (KERN_ERR UDC_NAME ": too big descriptor\n");    if (*ofs + len <= UDC_DESCRAM_SIZE) {        for (i = 0; i < len; i++)            writel (*p++, &tc_ramregs->DescRam[(*ofs) + i]);    }    *ofs += len;}/* *********************************************************************** *//* Control (endpoint zero) *//** * tc_in_ep0 - start transmit * @ep: */static voidtc_in_ep0 (struct usb_endpoint_instance *endpoint){    if (!endpoint)        return;    if (endpoint->tx_urb) {        struct urb *urb = endpoint->tx_urb;        dbg_ep0 (2, "length: %d sent %d",            endpoint->tx_urb->actual_length, endpoint->sent);        if ((urb->actual_length - endpoint->sent) > 0) {            if (readl (&tc_udcregs->DataSet[0]) & 1) {                printk (KERN_ERR UDC_NAME ": ep0 FIFO not empty\n");                return;            }            endpoint->last =                min_t (int, urb->actual_length - endpoint->sent,                endpoint->tx_packetSize);            tc_write_buffer (0, urb->buffer + endpoint->sent, endpoint->last);            if (endpoint->last < endpoint->tx_packetSize) {                dbg_ep0 (2, "EOP");                writel (~1, &tc_udcregs->EOP);            }        } else {            // XXX ZLP            endpoint->last = 0;            dbg_ep0 (2, "EOP");            writel (~1, &tc_udcregs->EOP);        }    } else if (endpoint->last == 0 ||        endpoint->last == endpoint->tx_packetSize) {        // XXX ZLP        dbg_ep0 (2, "EOP (last %d)", endpoint->last);        endpoint->last = 0;        writel (~1, &tc_udcregs->EOP);    }}static voidtc_out_ep0 (struct usb_endpoint_instance *endpoint){    printk (KERN_ERR UDC_NAME "tc_out_ep0: not supported.\n");}static voidtc_ep0_setup (void){    struct usb_device_request *req = &ep0_urb->device_request;    u8 *buf = (u8 *) req;    struct usb_endpoint_instance *endpoint = ep_endpoints[0];    if (!endpoint) {        dbg_udc (0, "no endpoint 0");        return;    }    /* store in little endian (see ep0_recv_setup) */    buf[0] = readl (&tc_udcregs->bmReqType);    buf[1] = readl (&tc_udcregs->bRequest);    buf[2] = readl (&tc_udcregs->wValueL);    buf[3] = readl (&tc_udcregs->wValueH);    buf[4] = readl (&tc_udcregs->wIndexL);    buf[5] = readl (&tc_udcregs->wIndexH);    buf[6] = readl (&tc_udcregs->wLengthL);    buf[7] = readl (&tc_udcregs->wLengthH);    writel (0, &tc_udcregs->SetupRecv);    dbg_ep0 (1,        "bmRequestType:%02x bRequest:%02x wValue:%04x wIndex:%04x wLength:%04x",        req->bmRequestType, req->bRequest, le16_to_cpu (req->wValue),        le16_to_cpu (req->wIndex), le16_to_cpu (req->wLength));    if (udc_device->device_state == STATE_DEFAULT &&        ((req->bmRequestType & USB_REQ_DIRECTION_MASK) == USB_REQ_HOST2DEVICE            || (req->bmRequestType & USB_REQ_TYPE_MASK) == USB_REQ_TYPE_CLASS)        && (readl (&tc_udcregs->Address) & 0xff)) {        /* first Host-to-Device setup or Class setup packet */        u8 new_address = readl (&tc_udcregs->Address) & 0xff;        /* SET_ADDRESS are processed by hardware only */        dbg_ep0 (1, "address assigned (%x)", new_address);        if (udc_device->address && udc_device->address != new_address)            printk (KERN_ERR "address changed\n");        udc_device->address = new_address;        usbd_device_event (udc_device, DEVICE_ADDRESS_ASSIGNED, 0);    }    if (usbd_recv_setup (ep0_urb)) {        dbg_ep0 (0, "usb_recv_setup failed, stalling");        udc_stall_ep (0);        return;    }    // check data direction    if ((req->bmRequestType & USB_REQ_DIRECTION_MASK) == USB_REQ_HOST2DEVICE) {        // should we setup to receive data        if (le16_to_cpu (req->wLength)) {            dbg_ep0 (1, "setup to read data %d", le16_to_cpu (req->wLength));            endpoint->rcv_urb = ep0_urb;            endpoint->rcv_urb->actual_length = 0;            tc_out_ep0 (endpoint);            return;        }        if (req->bRequest == USB_REQ_SET_CONFIGURATION) {            switch (req->wValue) {            case 0:                /* configured --> addressed */                usbd_device_event (udc_device, DEVICE_DE_CONFIGURED, 0);                writel (0, &tc_udcregs->UsbState);                dbg_udc (1, "UsbState %x", readl (&tc_udcregs->UsbState));                break;            default:                /* addressed --> configured */                //usbd_device_event(udc_device, DEVICE_CONFIGURED, 0);                writel (USBSTATE_CONFIGURED, &tc_udcregs->UsbState);                dbg_udc (1, "UsbState %x", readl (&tc_udcregs->UsbState));            }        }        dbg_ep0 (2, "EOP");        writel (~1, &tc_udcregs->EOP);        return;    }    // we should be sending data back    // check request length, zero is not legal    if (!le16_to_cpu (ep0_urb->device_request.wLength)) {        dbg_ep0 (0, "wLength zero, stall");        udc_stall_ep (0);        return;    }    // check that we have some data to send back, zero should not be possible    if (!ep0_urb->actual_length) {        dbg_ep0 (0, "no data, stall");        udc_stall_ep (0);        return;    }    // start sending    endpoint->tx_urb = ep0_urb;    endpoint->sent = 0;    endpoint->last = 0;    tc_in_ep0 (endpoint);}/* *********************************************************************** *//* Bulk OUT (recv) */static voidtc_mstrd_start (u32 start, u32 len, int eop){    u32 mst = readl (&tc_regs->MstSetting);    mst &= MST_RW_BITS & ~(MST_WR_ENA | MST_EOPB_ENA | MST_EOPB_DIS);    mst |= eop ? MST_EOPB_ENA : MST_EOPB_DIS;    mst |= MST_RD_ENA;    dbg_tx (2, "mstrd 0x%x 0x%x 0x%x", start, len, mst);    writel (start, &tc_regs->MstRdStart);    writel (start + len - 1, &tc_regs->MstRdEnd);    writel (mst, &tc_regs->MstSetting);}static voidtc_mstwr_start (u32 start, u32 len){    u32 mst = readl (&tc_regs->MstSetting);    mst &= MST_RW_BITS & ~(MST_RD_ENA);    mst |= MST_WR_ENA;    dbg_rx (2, "mstwr 0x%x 0x%x 0x%x", start, len, mst);    writel (start, &tc_regs->MstWrStart);    writel (start + len - 1, &tc_regs->MstWrEnd);    writel (mst | MST_WR_ENA, &tc_regs->MstSetting);}static unsigned long tc_do_task_ep;static void tc_start_out (unsigned int ep);static voidtc_do_task (void *data)                // runs as process{    unsigned long flags;    unsigned int ep;    if (!udc_device || udc_device->status != USBD_OK)        return;    for (ep = 0; ep < UDC_MAX_ENDPOINTS; ep++) {        if (test_and_clear_bit (ep, &tc_do_task_ep)) {            local_irq_save (flags);            while (!ep_endpoints[ep]->rcv_urb &&                !(ep_endpoints[ep]->rcv_urb =                    first_urb_detached_irq (&(ep_endpoints[ep]->rdy)))) {                local_irq_restore (flags);                /* usbd_recycle_urb will be called via device_bh */                run_task_queue (&tq_immediate);                local_irq_save (flags);            }            dbg_rx (1, "ep%d rcv urb available.", ep);            tc_start_out (ep);            local_irq_restore (flags);        }    }}

⌨️ 快捷键说明

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