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

📄 usb-musb.c

📁 xen虚拟机源代码安装包
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * "Inventra" High-speed Dual-Role Controller (MUSB-HDRC), Mentor Graphics, * USB2.0 OTG compliant core used in various chips. * * Copyright (C) 2008 Nokia Corporation * Written by Andrzej Zaborowski <andrew@openedhand.com> * * 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 or * (at your option) version 3 of the License. * * 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., 59 Temple Place, Suite 330, Boston, * MA 02111-1307 USA * * Only host-mode and non-DMA accesses are currently supported. */#include "qemu-common.h"#include "qemu-timer.h"#include "usb.h"#include "irq.h"/* Common USB registers */#define MUSB_HDRC_FADDR		0x00	/* 8-bit */#define MUSB_HDRC_POWER		0x01	/* 8-bit */#define MUSB_HDRC_INTRTX	0x02	/* 16-bit */#define MUSB_HDRC_INTRRX	0x04#define MUSB_HDRC_INTRTXE	0x06  #define MUSB_HDRC_INTRRXE	0x08  #define MUSB_HDRC_INTRUSB	0x0a	/* 8 bit */#define MUSB_HDRC_INTRUSBE	0x0b	/* 8 bit */#define MUSB_HDRC_FRAME		0x0c	/* 16-bit */#define MUSB_HDRC_INDEX		0x0e	/* 8 bit */#define MUSB_HDRC_TESTMODE	0x0f	/* 8 bit *//* Per-EP registers in indexed mode */#define MUSB_HDRC_EP_IDX	0x10	/* 8-bit *//* EP FIFOs */#define MUSB_HDRC_FIFO		0x20/* Additional Control Registers */#define	MUSB_HDRC_DEVCTL	0x60	/* 8 bit *//* These are indexed */#define MUSB_HDRC_TXFIFOSZ	0x62	/* 8 bit (see masks) */#define MUSB_HDRC_RXFIFOSZ	0x63	/* 8 bit (see masks) */#define MUSB_HDRC_TXFIFOADDR	0x64	/* 16 bit offset shifted right 3 */#define MUSB_HDRC_RXFIFOADDR	0x66	/* 16 bit offset shifted right 3 *//* Some more registers */#define MUSB_HDRC_VCTRL		0x68	/* 8 bit */#define MUSB_HDRC_HWVERS	0x6c	/* 8 bit *//* Added in HDRC 1.9(?) & MHDRC 1.4 *//* ULPI pass-through */#define MUSB_HDRC_ULPI_VBUSCTL	0x70#define MUSB_HDRC_ULPI_REGDATA	0x74#define MUSB_HDRC_ULPI_REGADDR	0x75#define MUSB_HDRC_ULPI_REGCTL	0x76/* Extended config & PHY control */#define MUSB_HDRC_ENDCOUNT	0x78	/* 8 bit */#define MUSB_HDRC_DMARAMCFG	0x79	/* 8 bit */#define MUSB_HDRC_PHYWAIT	0x7a	/* 8 bit */#define MUSB_HDRC_PHYVPLEN	0x7b	/* 8 bit */#define MUSB_HDRC_HS_EOF1	0x7c	/* 8 bit, units of 546.1 us */#define MUSB_HDRC_FS_EOF1	0x7d	/* 8 bit, units of 533.3 ns */#define MUSB_HDRC_LS_EOF1	0x7e	/* 8 bit, units of 1.067 us *//* Per-EP BUSCTL registers */#define MUSB_HDRC_BUSCTL	0x80/* Per-EP registers in flat mode */#define MUSB_HDRC_EP		0x100/* offsets to registers in flat model */#define MUSB_HDRC_TXMAXP	0x00	/* 16 bit apparently */#define MUSB_HDRC_TXCSR		0x02	/* 16 bit apparently */#define MUSB_HDRC_CSR0		MUSB_HDRC_TXCSR		/* re-used for EP0 */#define MUSB_HDRC_RXMAXP	0x04	/* 16 bit apparently */#define MUSB_HDRC_RXCSR		0x06	/* 16 bit apparently */#define MUSB_HDRC_RXCOUNT	0x08	/* 16 bit apparently */#define MUSB_HDRC_COUNT0	MUSB_HDRC_RXCOUNT	/* re-used for EP0 */#define MUSB_HDRC_TXTYPE	0x0a	/* 8 bit apparently */#define MUSB_HDRC_TYPE0		MUSB_HDRC_TXTYPE	/* re-used for EP0 */#define MUSB_HDRC_TXINTERVAL	0x0b	/* 8 bit apparently */#define MUSB_HDRC_NAKLIMIT0	MUSB_HDRC_TXINTERVAL	/* re-used for EP0 */#define MUSB_HDRC_RXTYPE	0x0c	/* 8 bit apparently */#define MUSB_HDRC_RXINTERVAL	0x0d	/* 8 bit apparently */#define MUSB_HDRC_FIFOSIZE	0x0f	/* 8 bit apparently */#define MUSB_HDRC_CONFIGDATA	MGC_O_HDRC_FIFOSIZE	/* re-used for EP0 *//* "Bus control" registers */#define MUSB_HDRC_TXFUNCADDR	0x00#define MUSB_HDRC_TXHUBADDR	0x02#define MUSB_HDRC_TXHUBPORT	0x03#define MUSB_HDRC_RXFUNCADDR	0x04#define MUSB_HDRC_RXHUBADDR	0x06#define MUSB_HDRC_RXHUBPORT	0x07/* * MUSBHDRC Register bit masks *//* POWER */#define MGC_M_POWER_ISOUPDATE		0x80 #define	MGC_M_POWER_SOFTCONN		0x40#define	MGC_M_POWER_HSENAB		0x20#define	MGC_M_POWER_HSMODE		0x10#define MGC_M_POWER_RESET		0x08#define MGC_M_POWER_RESUME		0x04#define MGC_M_POWER_SUSPENDM		0x02#define MGC_M_POWER_ENSUSPEND		0x01/* INTRUSB */#define MGC_M_INTR_SUSPEND		0x01#define MGC_M_INTR_RESUME		0x02#define MGC_M_INTR_RESET		0x04#define MGC_M_INTR_BABBLE		0x04#define MGC_M_INTR_SOF			0x08 #define MGC_M_INTR_CONNECT		0x10#define MGC_M_INTR_DISCONNECT		0x20#define MGC_M_INTR_SESSREQ		0x40#define MGC_M_INTR_VBUSERROR		0x80	/* FOR SESSION END */#define MGC_M_INTR_EP0			0x01	/* FOR EP0 INTERRUPT *//* DEVCTL */#define MGC_M_DEVCTL_BDEVICE		0x80   #define MGC_M_DEVCTL_FSDEV		0x40#define MGC_M_DEVCTL_LSDEV		0x20#define MGC_M_DEVCTL_VBUS		0x18#define MGC_S_DEVCTL_VBUS		3#define MGC_M_DEVCTL_HM			0x04#define MGC_M_DEVCTL_HR			0x02#define MGC_M_DEVCTL_SESSION		0x01/* TESTMODE */#define MGC_M_TEST_FORCE_HOST		0x80#define MGC_M_TEST_FIFO_ACCESS		0x40#define MGC_M_TEST_FORCE_FS		0x20#define MGC_M_TEST_FORCE_HS		0x10#define MGC_M_TEST_PACKET		0x08#define MGC_M_TEST_K			0x04#define MGC_M_TEST_J			0x02#define MGC_M_TEST_SE0_NAK		0x01/* CSR0 */#define	MGC_M_CSR0_FLUSHFIFO		0x0100#define MGC_M_CSR0_TXPKTRDY		0x0002#define MGC_M_CSR0_RXPKTRDY		0x0001/* CSR0 in Peripheral mode */#define MGC_M_CSR0_P_SVDSETUPEND	0x0080#define MGC_M_CSR0_P_SVDRXPKTRDY	0x0040#define MGC_M_CSR0_P_SENDSTALL		0x0020#define MGC_M_CSR0_P_SETUPEND		0x0010#define MGC_M_CSR0_P_DATAEND		0x0008#define MGC_M_CSR0_P_SENTSTALL		0x0004/* CSR0 in Host mode */#define MGC_M_CSR0_H_NO_PING		0x0800#define MGC_M_CSR0_H_WR_DATATOGGLE	0x0400	/* set to allow setting: */#define MGC_M_CSR0_H_DATATOGGLE		0x0200	/* data toggle control */#define	MGC_M_CSR0_H_NAKTIMEOUT		0x0080#define MGC_M_CSR0_H_STATUSPKT		0x0040#define MGC_M_CSR0_H_REQPKT		0x0020#define MGC_M_CSR0_H_ERROR		0x0010#define MGC_M_CSR0_H_SETUPPKT		0x0008#define MGC_M_CSR0_H_RXSTALL		0x0004/* CONFIGDATA */#define MGC_M_CONFIGDATA_MPRXE		0x80	/* auto bulk pkt combining */#define MGC_M_CONFIGDATA_MPTXE		0x40	/* auto bulk pkt splitting */#define MGC_M_CONFIGDATA_BIGENDIAN	0x20#define MGC_M_CONFIGDATA_HBRXE		0x10	/* HB-ISO for RX */#define MGC_M_CONFIGDATA_HBTXE		0x08	/* HB-ISO for TX */#define MGC_M_CONFIGDATA_DYNFIFO	0x04	/* dynamic FIFO sizing */#define MGC_M_CONFIGDATA_SOFTCONE	0x02	/* SoftConnect */#define MGC_M_CONFIGDATA_UTMIDW		0x01	/* Width, 0 => 8b, 1 => 16b *//* TXCSR in Peripheral and Host mode */#define MGC_M_TXCSR_AUTOSET		0x8000#define MGC_M_TXCSR_ISO			0x4000#define MGC_M_TXCSR_MODE		0x2000#define MGC_M_TXCSR_DMAENAB		0x1000#define MGC_M_TXCSR_FRCDATATOG		0x0800#define MGC_M_TXCSR_DMAMODE		0x0400#define MGC_M_TXCSR_CLRDATATOG		0x0040#define MGC_M_TXCSR_FLUSHFIFO		0x0008#define MGC_M_TXCSR_FIFONOTEMPTY	0x0002#define MGC_M_TXCSR_TXPKTRDY		0x0001/* TXCSR in Peripheral mode */#define MGC_M_TXCSR_P_INCOMPTX		0x0080#define MGC_M_TXCSR_P_SENTSTALL		0x0020#define MGC_M_TXCSR_P_SENDSTALL		0x0010#define MGC_M_TXCSR_P_UNDERRUN		0x0004/* TXCSR in Host mode */#define MGC_M_TXCSR_H_WR_DATATOGGLE	0x0200#define MGC_M_TXCSR_H_DATATOGGLE	0x0100#define MGC_M_TXCSR_H_NAKTIMEOUT	0x0080#define MGC_M_TXCSR_H_RXSTALL		0x0020#define MGC_M_TXCSR_H_ERROR		0x0004/* RXCSR in Peripheral and Host mode */#define MGC_M_RXCSR_AUTOCLEAR		0x8000#define MGC_M_RXCSR_DMAENAB		0x2000#define MGC_M_RXCSR_DISNYET		0x1000#define MGC_M_RXCSR_DMAMODE		0x0800#define MGC_M_RXCSR_INCOMPRX		0x0100#define MGC_M_RXCSR_CLRDATATOG		0x0080#define MGC_M_RXCSR_FLUSHFIFO		0x0010#define MGC_M_RXCSR_DATAERROR		0x0008#define MGC_M_RXCSR_FIFOFULL		0x0002#define MGC_M_RXCSR_RXPKTRDY		0x0001/* RXCSR in Peripheral mode */#define MGC_M_RXCSR_P_ISO		0x4000#define MGC_M_RXCSR_P_SENTSTALL		0x0040#define MGC_M_RXCSR_P_SENDSTALL		0x0020#define MGC_M_RXCSR_P_OVERRUN		0x0004/* RXCSR in Host mode */#define MGC_M_RXCSR_H_AUTOREQ		0x4000#define MGC_M_RXCSR_H_WR_DATATOGGLE	0x0400#define MGC_M_RXCSR_H_DATATOGGLE	0x0200#define MGC_M_RXCSR_H_RXSTALL		0x0040#define MGC_M_RXCSR_H_REQPKT		0x0020#define MGC_M_RXCSR_H_ERROR		0x0004/* HUBADDR */#define MGC_M_HUBADDR_MULTI_TT		0x80/* ULPI: Added in HDRC 1.9(?) & MHDRC 1.4 */#define MGC_M_ULPI_VBCTL_USEEXTVBUSIND	0x02#define MGC_M_ULPI_VBCTL_USEEXTVBUS	0x01#define MGC_M_ULPI_REGCTL_INT_ENABLE	0x08#define MGC_M_ULPI_REGCTL_READNOTWRITE	0x04#define MGC_M_ULPI_REGCTL_COMPLETE	0x02#define MGC_M_ULPI_REGCTL_REG		0x01static void musb_attach(USBPort *port, USBDevice *dev);struct musb_s {    qemu_irq *irqs;    USBPort port;    int idx;    uint8_t devctl;    uint8_t power;    uint8_t faddr;    uint8_t intr;    uint8_t mask;    uint16_t tx_intr;    uint16_t tx_mask;    uint16_t rx_intr;    uint16_t rx_mask;    int setup_len;    int session;    uint32_t buf[0x2000];    struct musb_ep_s {        uint16_t faddr[2];        uint8_t haddr[2];        uint8_t hport[2];        uint16_t csr[2];        uint16_t maxp[2];        uint16_t rxcount;        uint8_t type[2];        uint8_t interval[2];        uint8_t config;        uint8_t fifosize;        int timeout[2];	/* Always in microframes */        uint32_t *buf[2];        int fifolen[2];        int fifostart[2];        int fifoaddr[2];        USBPacket packey[2];        int status[2];        int ext_size[2];        /* For callbacks' use */        int epnum;        int interrupt[2];        struct musb_s *musb;        USBCallback *delayed_cb[2];        QEMUTimer *intv_timer[2];        /* Duplicating the world since 2008!...  probably we should have 32         * logical, single endpoints instead.  */    } ep[16];} *musb_init(qemu_irq *irqs){    struct musb_s *s = qemu_mallocz(sizeof(*s));    int i;    s->irqs = irqs;    s->faddr = 0x00;    s->power = MGC_M_POWER_HSENAB;    s->tx_intr = 0x0000;    s->rx_intr = 0x0000;    s->tx_mask = 0xffff;    s->rx_mask = 0xffff;    s->intr = 0x00;    s->mask = 0x06;    s->idx = 0;    /* TODO: _DW */    s->ep[0].config = MGC_M_CONFIGDATA_SOFTCONE | MGC_M_CONFIGDATA_DYNFIFO;    for (i = 0; i < 16; i ++) {        s->ep[i].fifosize = 64;        s->ep[i].maxp[0] = 0x40;        s->ep[i].maxp[1] = 0x40;        s->ep[i].musb = s;        s->ep[i].epnum = i;    }    qemu_register_usb_port(&s->port, s, 0, musb_attach);    return s;}static void musb_vbus_set(struct musb_s *s, int level){    if (level)        s->devctl |= 3 << MGC_S_DEVCTL_VBUS;    else        s->devctl &= ~MGC_M_DEVCTL_VBUS;    qemu_set_irq(s->irqs[musb_set_vbus], level);}static void musb_intr_set(struct musb_s *s, int line, int level){    if (!level) {        s->intr &= ~(1 << line);        qemu_irq_lower(s->irqs[line]);    } else if (s->mask & (1 << line)) {        s->intr |= 1 << line;        qemu_irq_raise(s->irqs[line]);    }}static void musb_tx_intr_set(struct musb_s *s, int line, int level){    if (!level) {        s->tx_intr &= ~(1 << line);        if (!s->tx_intr)            qemu_irq_lower(s->irqs[musb_irq_tx]);    } else if (s->tx_mask & (1 << line)) {        s->tx_intr |= 1 << line;        qemu_irq_raise(s->irqs[musb_irq_tx]);    }}static void musb_rx_intr_set(struct musb_s *s, int line, int level){    if (line) {        if (!level) {            s->rx_intr &= ~(1 << line);            if (!s->rx_intr)                qemu_irq_lower(s->irqs[musb_irq_rx]);        } else if (s->rx_mask & (1 << line)) {            s->rx_intr |= 1 << line;            qemu_irq_raise(s->irqs[musb_irq_rx]);        }    } else        musb_tx_intr_set(s, line, level);}uint32_t musb_core_intr_get(struct musb_s *s){    return (s->rx_intr << 15) | s->tx_intr;}void musb_core_intr_clear(struct musb_s *s, uint32_t mask){    if (s->rx_intr) {        s->rx_intr &= mask >> 15;        if (!s->rx_intr)            qemu_irq_lower(s->irqs[musb_irq_rx]);    }    if (s->tx_intr) {        s->tx_intr &= mask & 0xffff;        if (!s->tx_intr)            qemu_irq_lower(s->irqs[musb_irq_tx]);    }}void musb_set_size(struct musb_s *s, int epnum, int size, int is_tx){    s->ep[epnum].ext_size[!is_tx] = size;    s->ep[epnum].fifostart[0] = 0;    s->ep[epnum].fifostart[1] = 0;    s->ep[epnum].fifolen[0] = 0;    s->ep[epnum].fifolen[1] = 0;}static void musb_session_update(struct musb_s *s, int prev_dev, int prev_sess){    int detect_prev = prev_dev && prev_sess;    int detect = !!s->port.dev && s->session;    if (detect && !detect_prev) {        /* Let's skip the ID pin sense and VBUS sense formalities and         * and signal a successful SRP directly.  This should work at least         * for the Linux driver stack.  */        musb_intr_set(s, musb_irq_connect, 1);        if (s->port.dev->speed == USB_SPEED_LOW) {            s->devctl &= ~MGC_M_DEVCTL_FSDEV;            s->devctl |= MGC_M_DEVCTL_LSDEV;        } else {            s->devctl |= MGC_M_DEVCTL_FSDEV;            s->devctl &= ~MGC_M_DEVCTL_LSDEV;        }        /* A-mode?  */        s->devctl &= ~MGC_M_DEVCTL_BDEVICE;        /* Host-mode bit?  */        s->devctl |= MGC_M_DEVCTL_HM;#if 1        musb_vbus_set(s, 1);#endif    } else if (!detect && detect_prev) {#if 1        musb_vbus_set(s, 0);#endif    }}/* Attach or detach a device on our only port.  */static void musb_attach(USBPort *port, USBDevice *dev){    struct musb_s *s = (struct musb_s *) port->opaque;    USBDevice *curr;    port = &s->port;    curr = port->dev;    if (dev) {        if (curr) {            usb_attach(port, NULL);            /* TODO: signal some interrupts */        }        musb_intr_set(s, musb_irq_vbus_request, 1);        /* Send the attach message to device */        usb_send_msg(dev, USB_MSG_ATTACH);    } else if (curr) {        /* Send the detach message */        usb_send_msg(curr, USB_MSG_DETACH);        musb_intr_set(s, musb_irq_disconnect, 1);    }    port->dev = dev;    musb_session_update(s, !!curr, s->session);}static inline void musb_cb_tick0(void *opaque){    struct musb_ep_s *ep = (struct musb_ep_s *) opaque;    ep->delayed_cb[0](&ep->packey[0], opaque);

⌨️ 快捷键说明

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