1
0
Fork 0

Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6

* git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6: (143 commits)
  USB: xhci depends on PCI.
  USB: xhci: Add Makefile, MAINTAINERS, and Kconfig entries.
  USB: xhci: Respect critical sections.
  USB: xHCI: Fix interrupt moderation.
  USB: xhci: Remove packed attribute from structures.
  usb; xhci: Fix TRB offset calculations.
  USB: xhci: replace if-elseif-else with switch-case
  USB: xhci: Make xhci-mem.c include linux/dmapool.h
  USB: xhci: drop spinlock in xhci_urb_enqueue() error path.
  USB: Change names of SuperSpeed ep companion descriptor structs.
  USB: xhci: Avoid compiler reordering in Link TRB giveback.
  USB: xhci: Clean up xhci_irq() function.
  USB: xhci: Avoid global namespace pollution.
  USB: xhci: Fix Link TRB handoff bit twiddling.
  USB: xhci: Fix register write order.
  USB: xhci: fix some compiler warnings in xhci.h
  USB: xhci: fix lots of compiler warnings.
  USB: xhci: use xhci_handle_event instead of handle_event
  USB: xhci: URB cancellation support.
  USB: xhci: Scatter gather list support for bulk transfers.
  ...
hifive-unleashed-5.1
Linus Torvalds 2009-06-16 13:06:10 -07:00
commit e1f5b94fd0
164 changed files with 21017 additions and 2150 deletions

View File

@ -6165,6 +6165,12 @@ L: linux-wireless@vger.kernel.org
S: Maintained
F: drivers/net/wireless/rndis_wlan.c
USB XHCI DRIVER
P: Sarah Sharp
M: sarah.a.sharp@intel.com
L: linux-usb@vger.kernel.org
S: Supported
USB ZC0301 DRIVER
P: Luca Risolia
M: luca.risolia@studio.unibo.it

View File

@ -0,0 +1,50 @@
/* arch/arm/plat-s3c/include/plat/regs-usb-hsotg-phy.h
*
* Copyright 2008 Openmoko, Inc.
* Copyright 2008 Simtec Electronics
* http://armlinux.simtec.co.uk/
* Ben Dooks <ben@simtec.co.uk>
*
* S3C - USB2.0 Highspeed/OtG device PHY registers
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
/* Note, this is a seperate header file as some of the clock framework
* needs to touch this if the clk_48m is used as the USB OHCI or other
* peripheral source.
*/
#ifndef __PLAT_S3C64XX_REGS_USB_HSOTG_PHY_H
#define __PLAT_S3C64XX_REGS_USB_HSOTG_PHY_H __FILE__
/* S3C64XX_PA_USB_HSPHY */
#define S3C_HSOTG_PHYREG(x) ((x) + S3C_VA_USB_HSPHY)
#define S3C_PHYPWR S3C_HSOTG_PHYREG(0x00)
#define SRC_PHYPWR_OTG_DISABLE (1 << 4)
#define SRC_PHYPWR_ANALOG_POWERDOWN (1 << 3)
#define SRC_PHYPWR_FORCE_SUSPEND (1 << 1)
#define S3C_PHYCLK S3C_HSOTG_PHYREG(0x04)
#define S3C_PHYCLK_MODE_USB11 (1 << 6)
#define S3C_PHYCLK_EXT_OSC (1 << 5)
#define S3C_PHYCLK_CLK_FORCE (1 << 4)
#define S3C_PHYCLK_ID_PULL (1 << 2)
#define S3C_PHYCLK_CLKSEL_MASK (0x3 << 0)
#define S3C_PHYCLK_CLKSEL_SHIFT (0)
#define S3C_PHYCLK_CLKSEL_48M (0x0 << 0)
#define S3C_PHYCLK_CLKSEL_12M (0x2 << 0)
#define S3C_PHYCLK_CLKSEL_24M (0x3 << 0)
#define S3C_RSTCON S3C_HSOTG_PHYREG(0x08)
#define S3C_RSTCON_PHYCLK (1 << 2)
#define S3C_RSTCON_HCLK (1 << 2)
#define S3C_RSTCON_PHY (1 << 0)
#define S3C_PHYTUNE S3C_HSOTG_PHYREG(0x20)
#endif /* __PLAT_S3C64XX_REGS_USB_HSOTG_PHY_H */

View File

@ -0,0 +1,377 @@
/* arch/arm/plat-s3c/include/plat/regs-usb-hsotg.h
*
* Copyright 2008 Openmoko, Inc.
* Copyright 2008 Simtec Electronics
* http://armlinux.simtec.co.uk/
* Ben Dooks <ben@simtec.co.uk>
*
* S3C - USB2.0 Highspeed/OtG device block registers
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#ifndef __PLAT_S3C64XX_REGS_USB_HSOTG_H
#define __PLAT_S3C64XX_REGS_USB_HSOTG_H __FILE__
#define S3C_HSOTG_REG(x) (x)
#define S3C_GOTGCTL S3C_HSOTG_REG(0x000)
#define S3C_GOTGCTL_BSESVLD (1 << 19)
#define S3C_GOTGCTL_ASESVLD (1 << 18)
#define S3C_GOTGCTL_DBNC_SHORT (1 << 17)
#define S3C_GOTGCTL_CONID_B (1 << 16)
#define S3C_GOTGCTL_DEVHNPEN (1 << 11)
#define S3C_GOTGCTL_HSSETHNPEN (1 << 10)
#define S3C_GOTGCTL_HNPREQ (1 << 9)
#define S3C_GOTGCTL_HSTNEGSCS (1 << 8)
#define S3C_GOTGCTL_SESREQ (1 << 1)
#define S3C_GOTGCTL_SESREQSCS (1 << 0)
#define S3C_GOTGINT S3C_HSOTG_REG(0x004)
#define S3C_GOTGINT_DbnceDone (1 << 19)
#define S3C_GOTGINT_ADevTOUTChg (1 << 18)
#define S3C_GOTGINT_HstNegDet (1 << 17)
#define S3C_GOTGINT_HstnegSucStsChng (1 << 9)
#define S3C_GOTGINT_SesReqSucStsChng (1 << 8)
#define S3C_GOTGINT_SesEndDet (1 << 2)
#define S3C_GAHBCFG S3C_HSOTG_REG(0x008)
#define S3C_GAHBCFG_PTxFEmpLvl (1 << 8)
#define S3C_GAHBCFG_NPTxFEmpLvl (1 << 7)
#define S3C_GAHBCFG_DMAEn (1 << 5)
#define S3C_GAHBCFG_HBstLen_MASK (0xf << 1)
#define S3C_GAHBCFG_HBstLen_SHIFT (1)
#define S3C_GAHBCFG_HBstLen_Single (0x0 << 1)
#define S3C_GAHBCFG_HBstLen_Incr (0x1 << 1)
#define S3C_GAHBCFG_HBstLen_Incr4 (0x3 << 1)
#define S3C_GAHBCFG_HBstLen_Incr8 (0x5 << 1)
#define S3C_GAHBCFG_HBstLen_Incr16 (0x7 << 1)
#define S3C_GAHBCFG_GlblIntrEn (1 << 0)
#define S3C_GUSBCFG S3C_HSOTG_REG(0x00C)
#define S3C_GUSBCFG_PHYLPClkSel (1 << 15)
#define S3C_GUSBCFG_HNPCap (1 << 9)
#define S3C_GUSBCFG_SRPCap (1 << 8)
#define S3C_GUSBCFG_PHYIf16 (1 << 3)
#define S3C_GUSBCFG_TOutCal_MASK (0x7 << 0)
#define S3C_GUSBCFG_TOutCal_SHIFT (0)
#define S3C_GUSBCFG_TOutCal_LIMIT (0x7)
#define S3C_GUSBCFG_TOutCal(_x) ((_x) << 0)
#define S3C_GRSTCTL S3C_HSOTG_REG(0x010)
#define S3C_GRSTCTL_AHBIdle (1 << 31)
#define S3C_GRSTCTL_DMAReq (1 << 30)
#define S3C_GRSTCTL_TxFNum_MASK (0x1f << 6)
#define S3C_GRSTCTL_TxFNum_SHIFT (6)
#define S3C_GRSTCTL_TxFNum_LIMIT (0x1f)
#define S3C_GRSTCTL_TxFNum(_x) ((_x) << 6)
#define S3C_GRSTCTL_TxFFlsh (1 << 5)
#define S3C_GRSTCTL_RxFFlsh (1 << 4)
#define S3C_GRSTCTL_INTknQFlsh (1 << 3)
#define S3C_GRSTCTL_FrmCntrRst (1 << 2)
#define S3C_GRSTCTL_HSftRst (1 << 1)
#define S3C_GRSTCTL_CSftRst (1 << 0)
#define S3C_GINTSTS S3C_HSOTG_REG(0x014)
#define S3C_GINTMSK S3C_HSOTG_REG(0x018)
#define S3C_GINTSTS_WkUpInt (1 << 31)
#define S3C_GINTSTS_SessReqInt (1 << 30)
#define S3C_GINTSTS_DisconnInt (1 << 29)
#define S3C_GINTSTS_ConIDStsChng (1 << 28)
#define S3C_GINTSTS_PTxFEmp (1 << 26)
#define S3C_GINTSTS_HChInt (1 << 25)
#define S3C_GINTSTS_PrtInt (1 << 24)
#define S3C_GINTSTS_FetSusp (1 << 22)
#define S3C_GINTSTS_incompIP (1 << 21)
#define S3C_GINTSTS_IncomplSOIN (1 << 20)
#define S3C_GINTSTS_OEPInt (1 << 19)
#define S3C_GINTSTS_IEPInt (1 << 18)
#define S3C_GINTSTS_EPMis (1 << 17)
#define S3C_GINTSTS_EOPF (1 << 15)
#define S3C_GINTSTS_ISOutDrop (1 << 14)
#define S3C_GINTSTS_EnumDone (1 << 13)
#define S3C_GINTSTS_USBRst (1 << 12)
#define S3C_GINTSTS_USBSusp (1 << 11)
#define S3C_GINTSTS_ErlySusp (1 << 10)
#define S3C_GINTSTS_GOUTNakEff (1 << 7)
#define S3C_GINTSTS_GINNakEff (1 << 6)
#define S3C_GINTSTS_NPTxFEmp (1 << 5)
#define S3C_GINTSTS_RxFLvl (1 << 4)
#define S3C_GINTSTS_SOF (1 << 3)
#define S3C_GINTSTS_OTGInt (1 << 2)
#define S3C_GINTSTS_ModeMis (1 << 1)
#define S3C_GINTSTS_CurMod_Host (1 << 0)
#define S3C_GRXSTSR S3C_HSOTG_REG(0x01C)
#define S3C_GRXSTSP S3C_HSOTG_REG(0x020)
#define S3C_GRXSTS_FN_MASK (0x7f << 25)
#define S3C_GRXSTS_FN_SHIFT (25)
#define S3C_GRXSTS_PktSts_MASK (0xf << 17)
#define S3C_GRXSTS_PktSts_SHIFT (17)
#define S3C_GRXSTS_PktSts_GlobalOutNAK (0x1 << 17)
#define S3C_GRXSTS_PktSts_OutRX (0x2 << 17)
#define S3C_GRXSTS_PktSts_OutDone (0x3 << 17)
#define S3C_GRXSTS_PktSts_SetupDone (0x4 << 17)
#define S3C_GRXSTS_PktSts_SetupRX (0x6 << 17)
#define S3C_GRXSTS_DPID_MASK (0x3 << 15)
#define S3C_GRXSTS_DPID_SHIFT (15)
#define S3C_GRXSTS_ByteCnt_MASK (0x7ff << 4)
#define S3C_GRXSTS_ByteCnt_SHIFT (4)
#define S3C_GRXSTS_EPNum_MASK (0xf << 0)
#define S3C_GRXSTS_EPNum_SHIFT (0)
#define S3C_GRXFSIZ S3C_HSOTG_REG(0x024)
#define S3C_GNPTXFSIZ S3C_HSOTG_REG(0x028)
#define S3C_GNPTXFSIZ_NPTxFDep_MASK (0xffff << 16)
#define S3C_GNPTXFSIZ_NPTxFDep_SHIFT (16)
#define S3C_GNPTXFSIZ_NPTxFDep_LIMIT (0xffff)
#define S3C_GNPTXFSIZ_NPTxFDep(_x) ((_x) << 16)
#define S3C_GNPTXFSIZ_NPTxFStAddr_MASK (0xffff << 0)
#define S3C_GNPTXFSIZ_NPTxFStAddr_SHIFT (0)
#define S3C_GNPTXFSIZ_NPTxFStAddr_LIMIT (0xffff)
#define S3C_GNPTXFSIZ_NPTxFStAddr(_x) ((_x) << 0)
#define S3C_GNPTXSTS S3C_HSOTG_REG(0x02C)
#define S3C_GNPTXSTS_NPtxQTop_MASK (0x7f << 24)
#define S3C_GNPTXSTS_NPtxQTop_SHIFT (24)
#define S3C_GNPTXSTS_NPTxQSpcAvail_MASK (0xff << 16)
#define S3C_GNPTXSTS_NPTxQSpcAvail_SHIFT (16)
#define S3C_GNPTXSTS_NPTxQSpcAvail_GET(_v) (((_v) >> 16) & 0xff)
#define S3C_GNPTXSTS_NPTxFSpcAvail_MASK (0xffff << 0)
#define S3C_GNPTXSTS_NPTxFSpcAvail_SHIFT (0)
#define S3C_GNPTXSTS_NPTxFSpcAvail_GET(_v) (((_v) >> 0) & 0xffff)
#define S3C_HPTXFSIZ S3C_HSOTG_REG(0x100)
#define S3C_DPTXFSIZn(_a) S3C_HSOTG_REG(0x104 + (((_a) - 1) * 4))
#define S3C_DPTXFSIZn_DPTxFSize_MASK (0xffff << 16)
#define S3C_DPTXFSIZn_DPTxFSize_SHIFT (16)
#define S3C_DPTXFSIZn_DPTxFSize_GET(_v) (((_v) >> 16) & 0xffff)
#define S3C_DPTXFSIZn_DPTxFSize_LIMIT (0xffff)
#define S3C_DPTXFSIZn_DPTxFSize(_x) ((_x) << 16)
#define S3C_DPTXFSIZn_DPTxFStAddr_MASK (0xffff << 0)
#define S3C_DPTXFSIZn_DPTxFStAddr_SHIFT (0)
/* Device mode registers */
#define S3C_DCFG S3C_HSOTG_REG(0x800)
#define S3C_DCFG_EPMisCnt_MASK (0x1f << 18)
#define S3C_DCFG_EPMisCnt_SHIFT (18)
#define S3C_DCFG_EPMisCnt_LIMIT (0x1f)
#define S3C_DCFG_EPMisCnt(_x) ((_x) << 18)
#define S3C_DCFG_PerFrInt_MASK (0x3 << 11)
#define S3C_DCFG_PerFrInt_SHIFT (11)
#define S3C_DCFG_PerFrInt_LIMIT (0x3)
#define S3C_DCFG_PerFrInt(_x) ((_x) << 11)
#define S3C_DCFG_DevAddr_MASK (0x7f << 4)
#define S3C_DCFG_DevAddr_SHIFT (4)
#define S3C_DCFG_DevAddr_LIMIT (0x7f)
#define S3C_DCFG_DevAddr(_x) ((_x) << 4)
#define S3C_DCFG_NZStsOUTHShk (1 << 2)
#define S3C_DCFG_DevSpd_MASK (0x3 << 0)
#define S3C_DCFG_DevSpd_SHIFT (0)
#define S3C_DCFG_DevSpd_HS (0x0 << 0)
#define S3C_DCFG_DevSpd_FS (0x1 << 0)
#define S3C_DCFG_DevSpd_LS (0x2 << 0)
#define S3C_DCFG_DevSpd_FS48 (0x3 << 0)
#define S3C_DCTL S3C_HSOTG_REG(0x804)
#define S3C_DCTL_PWROnPrgDone (1 << 11)
#define S3C_DCTL_CGOUTNak (1 << 10)
#define S3C_DCTL_SGOUTNak (1 << 9)
#define S3C_DCTL_CGNPInNAK (1 << 8)
#define S3C_DCTL_SGNPInNAK (1 << 7)
#define S3C_DCTL_TstCtl_MASK (0x7 << 4)
#define S3C_DCTL_TstCtl_SHIFT (4)
#define S3C_DCTL_GOUTNakSts (1 << 3)
#define S3C_DCTL_GNPINNakSts (1 << 2)
#define S3C_DCTL_SftDiscon (1 << 1)
#define S3C_DCTL_RmtWkUpSig (1 << 0)
#define S3C_DSTS S3C_HSOTG_REG(0x808)
#define S3C_DSTS_SOFFN_MASK (0x3fff << 8)
#define S3C_DSTS_SOFFN_SHIFT (8)
#define S3C_DSTS_SOFFN_LIMIT (0x3fff)
#define S3C_DSTS_SOFFN(_x) ((_x) << 8)
#define S3C_DSTS_ErraticErr (1 << 3)
#define S3C_DSTS_EnumSpd_MASK (0x3 << 1)
#define S3C_DSTS_EnumSpd_SHIFT (1)
#define S3C_DSTS_EnumSpd_HS (0x0 << 1)
#define S3C_DSTS_EnumSpd_FS (0x1 << 1)
#define S3C_DSTS_EnumSpd_LS (0x2 << 1)
#define S3C_DSTS_EnumSpd_FS48 (0x3 << 1)
#define S3C_DSTS_SuspSts (1 << 0)
#define S3C_DIEPMSK S3C_HSOTG_REG(0x810)
#define S3C_DIEPMSK_INEPNakEffMsk (1 << 6)
#define S3C_DIEPMSK_INTknEPMisMsk (1 << 5)
#define S3C_DIEPMSK_INTknTXFEmpMsk (1 << 4)
#define S3C_DIEPMSK_TimeOUTMsk (1 << 3)
#define S3C_DIEPMSK_AHBErrMsk (1 << 2)
#define S3C_DIEPMSK_EPDisbldMsk (1 << 1)
#define S3C_DIEPMSK_XferComplMsk (1 << 0)
#define S3C_DOEPMSK S3C_HSOTG_REG(0x814)
#define S3C_DOEPMSK_Back2BackSetup (1 << 6)
#define S3C_DOEPMSK_OUTTknEPdisMsk (1 << 4)
#define S3C_DOEPMSK_SetupMsk (1 << 3)
#define S3C_DOEPMSK_AHBErrMsk (1 << 2)
#define S3C_DOEPMSK_EPDisbldMsk (1 << 1)
#define S3C_DOEPMSK_XferComplMsk (1 << 0)
#define S3C_DAINT S3C_HSOTG_REG(0x818)
#define S3C_DAINTMSK S3C_HSOTG_REG(0x81C)
#define S3C_DAINT_OutEP_SHIFT (16)
#define S3C_DAINT_OutEP(x) (1 << ((x) + 16))
#define S3C_DAINT_InEP(x) (1 << (x))
#define S3C_DTKNQR1 S3C_HSOTG_REG(0x820)
#define S3C_DTKNQR2 S3C_HSOTG_REG(0x824)
#define S3C_DTKNQR3 S3C_HSOTG_REG(0x830)
#define S3C_DTKNQR4 S3C_HSOTG_REG(0x834)
#define S3C_DVBUSDIS S3C_HSOTG_REG(0x828)
#define S3C_DVBUSPULSE S3C_HSOTG_REG(0x82C)
#define S3C_DIEPCTL0 S3C_HSOTG_REG(0x900)
#define S3C_DOEPCTL0 S3C_HSOTG_REG(0xB00)
#define S3C_DIEPCTL(_a) S3C_HSOTG_REG(0x900 + ((_a) * 0x20))
#define S3C_DOEPCTL(_a) S3C_HSOTG_REG(0xB00 + ((_a) * 0x20))
/* EP0 specialness:
* bits[29..28] - reserved (no SetD0PID, SetD1PID)
* bits[25..22] - should always be zero, this isn't a periodic endpoint
* bits[10..0] - MPS setting differenct for EP0
*/
#define S3C_D0EPCTL_MPS_MASK (0x3 << 0)
#define S3C_D0EPCTL_MPS_SHIFT (0)
#define S3C_D0EPCTL_MPS_64 (0x0 << 0)
#define S3C_D0EPCTL_MPS_32 (0x1 << 0)
#define S3C_D0EPCTL_MPS_16 (0x2 << 0)
#define S3C_D0EPCTL_MPS_8 (0x3 << 0)
#define S3C_DxEPCTL_EPEna (1 << 31)
#define S3C_DxEPCTL_EPDis (1 << 30)
#define S3C_DxEPCTL_SetD1PID (1 << 29)
#define S3C_DxEPCTL_SetOddFr (1 << 29)
#define S3C_DxEPCTL_SetD0PID (1 << 28)
#define S3C_DxEPCTL_SetEvenFr (1 << 28)
#define S3C_DxEPCTL_SNAK (1 << 27)
#define S3C_DxEPCTL_CNAK (1 << 26)
#define S3C_DxEPCTL_TxFNum_MASK (0xf << 22)
#define S3C_DxEPCTL_TxFNum_SHIFT (22)
#define S3C_DxEPCTL_TxFNum_LIMIT (0xf)
#define S3C_DxEPCTL_TxFNum(_x) ((_x) << 22)
#define S3C_DxEPCTL_Stall (1 << 21)
#define S3C_DxEPCTL_Snp (1 << 20)
#define S3C_DxEPCTL_EPType_MASK (0x3 << 18)
#define S3C_DxEPCTL_EPType_SHIFT (18)
#define S3C_DxEPCTL_EPType_Control (0x0 << 18)
#define S3C_DxEPCTL_EPType_Iso (0x1 << 18)
#define S3C_DxEPCTL_EPType_Bulk (0x2 << 18)
#define S3C_DxEPCTL_EPType_Intterupt (0x3 << 18)
#define S3C_DxEPCTL_NAKsts (1 << 17)
#define S3C_DxEPCTL_DPID (1 << 16)
#define S3C_DxEPCTL_EOFrNum (1 << 16)
#define S3C_DxEPCTL_USBActEp (1 << 15)
#define S3C_DxEPCTL_NextEp_MASK (0xf << 11)
#define S3C_DxEPCTL_NextEp_SHIFT (11)
#define S3C_DxEPCTL_NextEp_LIMIT (0xf)
#define S3C_DxEPCTL_NextEp(_x) ((_x) << 11)
#define S3C_DxEPCTL_MPS_MASK (0x7ff << 0)
#define S3C_DxEPCTL_MPS_SHIFT (0)
#define S3C_DxEPCTL_MPS_LIMIT (0x7ff)
#define S3C_DxEPCTL_MPS(_x) ((_x) << 0)
#define S3C_DIEPINT(_a) S3C_HSOTG_REG(0x908 + ((_a) * 0x20))
#define S3C_DOEPINT(_a) S3C_HSOTG_REG(0xB08 + ((_a) * 0x20))
#define S3C_DxEPINT_INEPNakEff (1 << 6)
#define S3C_DxEPINT_Back2BackSetup (1 << 6)
#define S3C_DxEPINT_INTknEPMis (1 << 5)
#define S3C_DxEPINT_INTknTXFEmp (1 << 4)
#define S3C_DxEPINT_OUTTknEPdis (1 << 4)
#define S3C_DxEPINT_Timeout (1 << 3)
#define S3C_DxEPINT_Setup (1 << 3)
#define S3C_DxEPINT_AHBErr (1 << 2)
#define S3C_DxEPINT_EPDisbld (1 << 1)
#define S3C_DxEPINT_XferCompl (1 << 0)
#define S3C_DIEPTSIZ0 S3C_HSOTG_REG(0x910)
#define S3C_DIEPTSIZ0_PktCnt_MASK (0x3 << 19)
#define S3C_DIEPTSIZ0_PktCnt_SHIFT (19)
#define S3C_DIEPTSIZ0_PktCnt_LIMIT (0x3)
#define S3C_DIEPTSIZ0_PktCnt(_x) ((_x) << 19)
#define S3C_DIEPTSIZ0_XferSize_MASK (0x7f << 0)
#define S3C_DIEPTSIZ0_XferSize_SHIFT (0)
#define S3C_DIEPTSIZ0_XferSize_LIMIT (0x7f)
#define S3C_DIEPTSIZ0_XferSize(_x) ((_x) << 0)
#define DOEPTSIZ0 S3C_HSOTG_REG(0xB10)
#define S3C_DOEPTSIZ0_SUPCnt_MASK (0x3 << 29)
#define S3C_DOEPTSIZ0_SUPCnt_SHIFT (29)
#define S3C_DOEPTSIZ0_SUPCnt_LIMIT (0x3)
#define S3C_DOEPTSIZ0_SUPCnt(_x) ((_x) << 29)
#define S3C_DOEPTSIZ0_PktCnt (1 << 19)
#define S3C_DOEPTSIZ0_XferSize_MASK (0x7f << 0)
#define S3C_DOEPTSIZ0_XferSize_SHIFT (0)
#define S3C_DIEPTSIZ(_a) S3C_HSOTG_REG(0x910 + ((_a) * 0x20))
#define S3C_DOEPTSIZ(_a) S3C_HSOTG_REG(0xB10 + ((_a) * 0x20))
#define S3C_DxEPTSIZ_MC_MASK (0x3 << 29)
#define S3C_DxEPTSIZ_MC_SHIFT (29)
#define S3C_DxEPTSIZ_MC_LIMIT (0x3)
#define S3C_DxEPTSIZ_MC(_x) ((_x) << 29)
#define S3C_DxEPTSIZ_PktCnt_MASK (0x3ff << 19)
#define S3C_DxEPTSIZ_PktCnt_SHIFT (19)
#define S3C_DxEPTSIZ_PktCnt_GET(_v) (((_v) >> 19) & 0x3ff)
#define S3C_DxEPTSIZ_PktCnt_LIMIT (0x3ff)
#define S3C_DxEPTSIZ_PktCnt(_x) ((_x) << 19)
#define S3C_DxEPTSIZ_XferSize_MASK (0x7ffff << 0)
#define S3C_DxEPTSIZ_XferSize_SHIFT (0)
#define S3C_DxEPTSIZ_XferSize_GET(_v) (((_v) >> 0) & 0x7ffff)
#define S3C_DxEPTSIZ_XferSize_LIMIT (0x7ffff)
#define S3C_DxEPTSIZ_XferSize(_x) ((_x) << 0)
#define S3C_DIEPDMA(_a) S3C_HSOTG_REG(0x914 + ((_a) * 0x20))
#define S3C_DOEPDMA(_a) S3C_HSOTG_REG(0xB14 + ((_a) * 0x20))
#define S3C_EPFIFO(_a) S3C_HSOTG_REG(0x1000 + ((_a) * 0x1000))
#endif /* __PLAT_S3C64XX_REGS_USB_HSOTG_H */

View File

@ -24,6 +24,11 @@
#include <asm/setup.h>
#include "pci.h"
const char *pci_power_names[] = {
"error", "D0", "D1", "D2", "D3hot", "D3cold", "unknown",
};
EXPORT_SYMBOL_GPL(pci_power_names);
unsigned int pci_pm_d3_delay = PCI_PM_D3_WAIT;
#ifdef CONFIG_PCI_DOMAINS

View File

@ -2336,7 +2336,7 @@ static int ATEN2011_startup(struct usb_serial *serial)
return 0;
}
static void ATEN2011_shutdown(struct usb_serial *serial)
static void ATEN2011_release(struct usb_serial *serial)
{
int i;
struct ATENINTL_port *ATEN2011_port;
@ -2382,7 +2382,7 @@ static struct usb_serial_driver aten_serial_driver = {
.tiocmget = ATEN2011_tiocmget,
.tiocmset = ATEN2011_tiocmset,
.attach = ATEN2011_startup,
.shutdown = ATEN2011_shutdown,
.release = ATEN2011_release,
.read_bulk_callback = ATEN2011_bulk_in_callback,
.read_int_callback = ATEN2011_interrupt_callback,
};

View File

@ -64,6 +64,7 @@ config USB_ARCH_HAS_EHCI
config USB
tristate "Support for Host-side USB"
depends on USB_ARCH_HAS_HCD
select NLS # for UTF-8 strings
---help---
Universal Serial Bus (USB) is a specification for a serial bus
subsystem which offers higher speeds and more features than the

View File

@ -14,6 +14,7 @@ obj-$(CONFIG_USB_ISP116X_HCD) += host/
obj-$(CONFIG_USB_OHCI_HCD) += host/
obj-$(CONFIG_USB_UHCI_HCD) += host/
obj-$(CONFIG_USB_FHCI_HCD) += host/
obj-$(CONFIG_USB_XHCI_HCD) += host/
obj-$(CONFIG_USB_SL811_HCD) += host/
obj-$(CONFIG_USB_U132_HCD) += host/
obj-$(CONFIG_USB_R8A66597_HCD) += host/

View File

@ -937,9 +937,9 @@ static int acm_probe(struct usb_interface *intf,
int buflen = intf->altsetting->extralen;
struct usb_interface *control_interface;
struct usb_interface *data_interface;
struct usb_endpoint_descriptor *epctrl;
struct usb_endpoint_descriptor *epread;
struct usb_endpoint_descriptor *epwrite;
struct usb_endpoint_descriptor *epctrl = NULL;
struct usb_endpoint_descriptor *epread = NULL;
struct usb_endpoint_descriptor *epwrite = NULL;
struct usb_device *usb_dev = interface_to_usbdev(intf);
struct acm *acm;
int minor;
@ -952,6 +952,7 @@ static int acm_probe(struct usb_interface *intf,
unsigned long quirks;
int num_rx_buf;
int i;
int combined_interfaces = 0;
/* normal quirks */
quirks = (unsigned long)id->driver_info;
@ -1033,9 +1034,15 @@ next_desc:
data_interface = usb_ifnum_to_if(usb_dev, (data_interface_num = call_interface_num));
control_interface = intf;
} else {
dev_dbg(&intf->dev,
"No union descriptor, giving up\n");
return -ENODEV;
if (intf->cur_altsetting->desc.bNumEndpoints != 3) {
dev_dbg(&intf->dev,"No union descriptor, giving up\n");
return -ENODEV;
} else {
dev_warn(&intf->dev,"No union descriptor, testing for castrated device\n");
combined_interfaces = 1;
control_interface = data_interface = intf;
goto look_for_collapsed_interface;
}
}
} else {
control_interface = usb_ifnum_to_if(usb_dev, union_header->bMasterInterface0);
@ -1049,6 +1056,36 @@ next_desc:
if (data_interface_num != call_interface_num)
dev_dbg(&intf->dev, "Separate call control interface. That is not fully supported.\n");
if (control_interface == data_interface) {
/* some broken devices designed for windows work this way */
dev_warn(&intf->dev,"Control and data interfaces are not separated!\n");
combined_interfaces = 1;
/* a popular other OS doesn't use it */
quirks |= NO_CAP_LINE;
if (data_interface->cur_altsetting->desc.bNumEndpoints != 3) {
dev_err(&intf->dev, "This needs exactly 3 endpoints\n");
return -EINVAL;
}
look_for_collapsed_interface:
for (i = 0; i < 3; i++) {
struct usb_endpoint_descriptor *ep;
ep = &data_interface->cur_altsetting->endpoint[i].desc;
if (usb_endpoint_is_int_in(ep))
epctrl = ep;
else if (usb_endpoint_is_bulk_out(ep))
epwrite = ep;
else if (usb_endpoint_is_bulk_in(ep))
epread = ep;
else
return -EINVAL;
}
if (!epctrl || !epread || !epwrite)
return -ENODEV;
else
goto made_compressed_probe;
}
skip_normal_probe:
/*workaround for switched interfaces */
@ -1068,10 +1105,11 @@ skip_normal_probe:
}
/* Accept probe requests only for the control interface */
if (intf != control_interface)
if (!combined_interfaces && intf != control_interface)
return -ENODEV;
if (usb_interface_claimed(data_interface)) { /* valid in this context */
if (!combined_interfaces && usb_interface_claimed(data_interface)) {
/* valid in this context */
dev_dbg(&intf->dev, "The data interface isn't available\n");
return -EBUSY;
}
@ -1095,6 +1133,7 @@ skip_normal_probe:
epread = epwrite;
epwrite = t;
}
made_compressed_probe:
dbg("interfaces are valid");
for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++);
@ -1112,12 +1151,15 @@ skip_normal_probe:
ctrlsize = le16_to_cpu(epctrl->wMaxPacketSize);
readsize = le16_to_cpu(epread->wMaxPacketSize) *
(quirks == SINGLE_RX_URB ? 1 : 2);
acm->combined_interfaces = combined_interfaces;
acm->writesize = le16_to_cpu(epwrite->wMaxPacketSize) * 20;
acm->control = control_interface;
acm->data = data_interface;
acm->minor = minor;
acm->dev = usb_dev;
acm->ctrl_caps = ac_management_function;
if (quirks & NO_CAP_LINE)
acm->ctrl_caps &= ~USB_CDC_CAP_LINE;
acm->ctrlsize = ctrlsize;
acm->readsize = readsize;
acm->rx_buflimit = num_rx_buf;
@ -1223,9 +1265,10 @@ skip_normal_probe:
skip_countries:
usb_fill_int_urb(acm->ctrlurb, usb_dev,
usb_rcvintpipe(usb_dev, epctrl->bEndpointAddress),
acm->ctrl_buffer, ctrlsize, acm_ctrl_irq, acm,
epctrl->bInterval);
usb_rcvintpipe(usb_dev, epctrl->bEndpointAddress),
acm->ctrl_buffer, ctrlsize, acm_ctrl_irq, acm,
/* works around buggy devices */
epctrl->bInterval ? epctrl->bInterval : 0xff);
acm->ctrlurb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
acm->ctrlurb->transfer_dma = acm->ctrl_dma;
@ -1312,7 +1355,8 @@ static void acm_disconnect(struct usb_interface *intf)
acm->ctrl_dma);
acm_read_buffers_free(acm);
usb_driver_release_interface(&acm_driver, intf == acm->control ?
if (!acm->combined_interfaces)
usb_driver_release_interface(&acm_driver, intf == acm->control ?
acm->data : acm->control);
if (acm->port.count == 0) {
@ -1451,6 +1495,9 @@ static struct usb_device_id acm_ids[] = {
Maybe we should define a new
quirk for this. */
},
{ USB_DEVICE(0x1bbb, 0x0003), /* Alcatel OT-I650 */
.driver_info = NO_UNION_NORMAL, /* reports zero length descriptor */
},
/* control interfaces with various AT-command sets */
{ USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,

View File

@ -125,6 +125,7 @@ struct acm {
unsigned char clocal; /* termios CLOCAL */
unsigned int ctrl_caps; /* control capabilities from the class specific header */
unsigned int susp_count; /* number of suspended interfaces */
int combined_interfaces:1; /* control and data collapsed */
struct acm_wb *delayed_wb; /* write queued for a device about to be woken */
};
@ -133,3 +134,4 @@ struct acm {
/* constants describing various quirks and errors */
#define NO_UNION_NORMAL 1
#define SINGLE_RX_URB 2
#define NO_CAP_LINE 4

View File

@ -927,21 +927,27 @@ static long usbtmc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
switch (cmd) {
case USBTMC_IOCTL_CLEAR_OUT_HALT:
retval = usbtmc_ioctl_clear_out_halt(data);
break;
case USBTMC_IOCTL_CLEAR_IN_HALT:
retval = usbtmc_ioctl_clear_in_halt(data);
break;
case USBTMC_IOCTL_INDICATOR_PULSE:
retval = usbtmc_ioctl_indicator_pulse(data);
break;
case USBTMC_IOCTL_CLEAR:
retval = usbtmc_ioctl_clear(data);
break;
case USBTMC_IOCTL_ABORT_BULK_OUT:
retval = usbtmc_ioctl_abort_bulk_out(data);
break;
case USBTMC_IOCTL_ABORT_BULK_IN:
retval = usbtmc_ioctl_abort_bulk_in(data);
break;
}
mutex_unlock(&data->io_mutex);

View File

@ -28,7 +28,7 @@ comment "Miscellaneous USB options"
depends on USB
config USB_DEVICEFS
bool "USB device filesystem"
bool "USB device filesystem (DEPRECATED)" if EMBEDDED
depends on USB
---help---
If you say Y here (and to "/proc file system support" in the "File
@ -46,11 +46,15 @@ config USB_DEVICEFS
For the format of the various /proc/bus/usb/ files, please read
<file:Documentation/usb/proc_usb_info.txt>.
Usbfs files can't handle Access Control Lists (ACL), which are the
default way to grant access to USB devices for untrusted users of a
desktop system. The usbfs functionality is replaced by real
device-nodes managed by udev. These nodes live in /dev/bus/usb and
are used by libusb.
Modern Linux systems do not use this.
Usbfs entries are files and not character devices; usbfs can't
handle Access Control Lists (ACL) which are the default way to
grant access to USB devices for untrusted users of a desktop
system.
The usbfs functionality is replaced by real device-nodes managed by
udev. These nodes lived in /dev/bus/usb and are used by libusb.
config USB_DEVICE_CLASS
bool "USB device class-devices (DEPRECATED)"

View File

@ -4,14 +4,14 @@
usbcore-objs := usb.o hub.o hcd.o urb.o message.o driver.o \
config.o file.o buffer.o sysfs.o endpoint.o \
devio.o notify.o generic.o quirks.o
devio.o notify.o generic.o quirks.o devices.o
ifeq ($(CONFIG_PCI),y)
usbcore-objs += hcd-pci.o
endif
ifeq ($(CONFIG_USB_DEVICEFS),y)
usbcore-objs += inode.o devices.o
usbcore-objs += inode.o
endif
obj-$(CONFIG_USB) += usbcore.o

View File

@ -19,6 +19,32 @@ static inline const char *plural(int n)
return (n == 1 ? "" : "s");
}
/* FIXME: this is a kludge */
static int find_next_descriptor_more(unsigned char *buffer, int size,
int dt1, int dt2, int dt3, int *num_skipped)
{
struct usb_descriptor_header *h;
int n = 0;
unsigned char *buffer0 = buffer;
/* Find the next descriptor of type dt1 or dt2 or dt3 */
while (size > 0) {
h = (struct usb_descriptor_header *) buffer;
if (h->bDescriptorType == dt1 || h->bDescriptorType == dt2 ||
h->bDescriptorType == dt3)
break;
buffer += h->bLength;
size -= h->bLength;
++n;
}
/* Store the number of descriptors skipped and return the
* number of bytes skipped */
if (num_skipped)
*num_skipped = n;
return buffer - buffer0;
}
static int find_next_descriptor(unsigned char *buffer, int size,
int dt1, int dt2, int *num_skipped)
{
@ -43,6 +69,129 @@ static int find_next_descriptor(unsigned char *buffer, int size,
return buffer - buffer0;
}
static int usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno,
int inum, int asnum, struct usb_host_endpoint *ep,
int num_ep, unsigned char *buffer, int size)
{
unsigned char *buffer_start = buffer;
struct usb_ss_ep_comp_descriptor *desc;
int retval;
int num_skipped;
int max_tx;
int i;
/* Allocate space for the SS endpoint companion descriptor */
ep->ss_ep_comp = kzalloc(sizeof(struct usb_host_ss_ep_comp),
GFP_KERNEL);
if (!ep->ss_ep_comp)
return -ENOMEM;
desc = (struct usb_ss_ep_comp_descriptor *) buffer;
if (desc->bDescriptorType != USB_DT_SS_ENDPOINT_COMP) {
dev_warn(ddev, "No SuperSpeed endpoint companion for config %d "
" interface %d altsetting %d ep %d: "
"using minimum values\n",
cfgno, inum, asnum, ep->desc.bEndpointAddress);
ep->ss_ep_comp->desc.bLength = USB_DT_SS_EP_COMP_SIZE;
ep->ss_ep_comp->desc.bDescriptorType = USB_DT_SS_ENDPOINT_COMP;
ep->ss_ep_comp->desc.bMaxBurst = 0;
/*
* Leave bmAttributes as zero, which will mean no streams for
* bulk, and isoc won't support multiple bursts of packets.
* With bursts of only one packet, and a Mult of 1, the max
* amount of data moved per endpoint service interval is one
* packet.
*/
if (usb_endpoint_xfer_isoc(&ep->desc) ||
usb_endpoint_xfer_int(&ep->desc))
ep->ss_ep_comp->desc.wBytesPerInterval =
ep->desc.wMaxPacketSize;
/*
* The next descriptor is for an Endpoint or Interface,
* no extra descriptors to copy into the companion structure,
* and we didn't eat up any of the buffer.
*/
retval = 0;
goto valid;
}
memcpy(&ep->ss_ep_comp->desc, desc, USB_DT_SS_EP_COMP_SIZE);
desc = &ep->ss_ep_comp->desc;
buffer += desc->bLength;
size -= desc->bLength;
/* Eat up the other descriptors we don't care about */
ep->ss_ep_comp->extra = buffer;
i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT,
USB_DT_INTERFACE, &num_skipped);
ep->ss_ep_comp->extralen = i;
buffer += i;
size -= i;
retval = buffer - buffer_start + i;
if (num_skipped > 0)
dev_dbg(ddev, "skipped %d descriptor%s after %s\n",
num_skipped, plural(num_skipped),
"SuperSpeed endpoint companion");
/* Check the various values */
if (usb_endpoint_xfer_control(&ep->desc) && desc->bMaxBurst != 0) {
dev_warn(ddev, "Control endpoint with bMaxBurst = %d in "
"config %d interface %d altsetting %d ep %d: "
"setting to zero\n", desc->bMaxBurst,
cfgno, inum, asnum, ep->desc.bEndpointAddress);
desc->bMaxBurst = 0;
}
if (desc->bMaxBurst > 15) {
dev_warn(ddev, "Endpoint with bMaxBurst = %d in "
"config %d interface %d altsetting %d ep %d: "
"setting to 15\n", desc->bMaxBurst,
cfgno, inum, asnum, ep->desc.bEndpointAddress);
desc->bMaxBurst = 15;
}
if ((usb_endpoint_xfer_control(&ep->desc) || usb_endpoint_xfer_int(&ep->desc))
&& desc->bmAttributes != 0) {
dev_warn(ddev, "%s endpoint with bmAttributes = %d in "
"config %d interface %d altsetting %d ep %d: "
"setting to zero\n",
usb_endpoint_xfer_control(&ep->desc) ? "Control" : "Bulk",
desc->bmAttributes,
cfgno, inum, asnum, ep->desc.bEndpointAddress);
desc->bmAttributes = 0;
}
if (usb_endpoint_xfer_bulk(&ep->desc) && desc->bmAttributes > 16) {
dev_warn(ddev, "Bulk endpoint with more than 65536 streams in "
"config %d interface %d altsetting %d ep %d: "
"setting to max\n",
cfgno, inum, asnum, ep->desc.bEndpointAddress);
desc->bmAttributes = 16;
}
if (usb_endpoint_xfer_isoc(&ep->desc) && desc->bmAttributes > 2) {
dev_warn(ddev, "Isoc endpoint has Mult of %d in "
"config %d interface %d altsetting %d ep %d: "
"setting to 3\n", desc->bmAttributes + 1,
cfgno, inum, asnum, ep->desc.bEndpointAddress);
desc->bmAttributes = 2;
}
if (usb_endpoint_xfer_isoc(&ep->desc)) {
max_tx = ep->desc.wMaxPacketSize * (desc->bMaxBurst + 1) *
(desc->bmAttributes + 1);
} else if (usb_endpoint_xfer_int(&ep->desc)) {
max_tx = ep->desc.wMaxPacketSize * (desc->bMaxBurst + 1);
} else {
goto valid;
}
if (desc->wBytesPerInterval > max_tx) {
dev_warn(ddev, "%s endpoint with wBytesPerInterval of %d in "
"config %d interface %d altsetting %d ep %d: "
"setting to %d\n",
usb_endpoint_xfer_isoc(&ep->desc) ? "Isoc" : "Int",
desc->wBytesPerInterval,
cfgno, inum, asnum, ep->desc.bEndpointAddress,
max_tx);
desc->wBytesPerInterval = max_tx;
}
valid:
return retval;
}
static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
int asnum, struct usb_host_interface *ifp, int num_ep,
unsigned char *buffer, int size)
@ -50,7 +199,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
unsigned char *buffer0 = buffer;
struct usb_endpoint_descriptor *d;
struct usb_host_endpoint *endpoint;
int n, i, j;
int n, i, j, retval;
d = (struct usb_endpoint_descriptor *) buffer;
buffer += d->bLength;
@ -92,6 +241,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
if (usb_endpoint_xfer_int(d)) {
i = 1;
switch (to_usb_device(ddev)->speed) {
case USB_SPEED_SUPER:
case USB_SPEED_HIGH:
/* Many device manufacturers are using full-speed
* bInterval values in high-speed interrupt endpoint
@ -161,17 +311,39 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
cfgno, inum, asnum, d->bEndpointAddress,
maxp);
}
/* Allocate room for and parse any SS endpoint companion descriptors */
if (to_usb_device(ddev)->speed == USB_SPEED_SUPER) {
endpoint->extra = buffer;
i = find_next_descriptor_more(buffer, size, USB_DT_SS_ENDPOINT_COMP,
USB_DT_ENDPOINT, USB_DT_INTERFACE, &n);
endpoint->extralen = i;
buffer += i;
size -= i;
/* Skip over any Class Specific or Vendor Specific descriptors;
* find the next endpoint or interface descriptor */
endpoint->extra = buffer;
i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT,
USB_DT_INTERFACE, &n);
endpoint->extralen = i;
if (size > 0) {
retval = usb_parse_ss_endpoint_companion(ddev, cfgno,
inum, asnum, endpoint, num_ep, buffer,
size);
if (retval >= 0) {
buffer += retval;
retval = buffer - buffer0;
}
} else {
retval = buffer - buffer0;
}
} else {
/* Skip over any Class Specific or Vendor Specific descriptors;
* find the next endpoint or interface descriptor */
endpoint->extra = buffer;
i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT,
USB_DT_INTERFACE, &n);
endpoint->extralen = i;
retval = buffer - buffer0 + i;
}
if (n > 0)
dev_dbg(ddev, "skipped %d descriptor%s after %s\n",
n, plural(n), "endpoint");
return buffer - buffer0 + i;
return retval;
skip_to_next_endpoint_or_interface_descriptor:
i = find_next_descriptor(buffer, size, USB_DT_ENDPOINT,
@ -452,6 +624,8 @@ static int usb_parse_configuration(struct device *ddev, int cfgidx,
kref_init(&intfc->ref);
}
/* FIXME: parse the BOS descriptor */
/* Skip over any Class Specific or Vendor Specific descriptors;
* find the first interface descriptor */
config->extra = buffer;

View File

@ -154,16 +154,11 @@ static const struct usb_device_id *usb_match_dynamic_id(struct usb_interface *in
static int usb_probe_device(struct device *dev)
{
struct usb_device_driver *udriver = to_usb_device_driver(dev->driver);
struct usb_device *udev;
struct usb_device *udev = to_usb_device(dev);
int error = -ENODEV;
dev_dbg(dev, "%s\n", __func__);
if (!is_usb_device(dev)) /* Sanity check */
return error;
udev = to_usb_device(dev);
/* TODO: Add real matching code */
/* The device should always appear to be in use
@ -203,18 +198,13 @@ static void usb_cancel_queued_reset(struct usb_interface *iface)
static int usb_probe_interface(struct device *dev)
{
struct usb_driver *driver = to_usb_driver(dev->driver);
struct usb_interface *intf;
struct usb_device *udev;
struct usb_interface *intf = to_usb_interface(dev);
struct usb_device *udev = interface_to_usbdev(intf);
const struct usb_device_id *id;
int error = -ENODEV;
dev_dbg(dev, "%s\n", __func__);
if (is_usb_device(dev)) /* Sanity check */
return error;
intf = to_usb_interface(dev);
udev = interface_to_usbdev(intf);
intf->needs_binding = 0;
if (udev->authorized == 0) {
@ -385,7 +375,6 @@ void usb_driver_release_interface(struct usb_driver *driver,
struct usb_interface *iface)
{
struct device *dev = &iface->dev;
struct usb_device *udev = interface_to_usbdev(iface);
/* this should never happen, don't release something that's not ours */
if (!dev->driver || dev->driver != &driver->drvwrap.driver)
@ -394,23 +383,19 @@ void usb_driver_release_interface(struct usb_driver *driver,
/* don't release from within disconnect() */
if (iface->condition != USB_INTERFACE_BOUND)
return;
iface->condition = USB_INTERFACE_UNBINDING;
/* don't release if the interface hasn't been added yet */
/* Release via the driver core only if the interface
* has already been registered
*/
if (device_is_registered(dev)) {
iface->condition = USB_INTERFACE_UNBINDING;
device_release_driver(dev);
} else {
iface->condition = USB_INTERFACE_UNBOUND;
usb_cancel_queued_reset(iface);
down(&dev->sem);
usb_unbind_interface(dev);
dev->driver = NULL;
up(&dev->sem);
}
dev->driver = NULL;
usb_set_intfdata(iface, NULL);
usb_pm_lock(udev);
iface->condition = USB_INTERFACE_UNBOUND;
mark_quiesced(iface);
iface->needs_remote_wakeup = 0;
usb_pm_unlock(udev);
}
EXPORT_SYMBOL_GPL(usb_driver_release_interface);
@ -598,7 +583,7 @@ static int usb_device_match(struct device *dev, struct device_driver *drv)
/* TODO: Add real matching code */
return 1;
} else {
} else if (is_usb_interface(dev)) {
struct usb_interface *intf;
struct usb_driver *usb_drv;
const struct usb_device_id *id;
@ -630,11 +615,14 @@ static int usb_uevent(struct device *dev, struct kobj_uevent_env *env)
/* driver is often null here; dev_dbg() would oops */
pr_debug("usb %s: uevent\n", dev_name(dev));
if (is_usb_device(dev))
if (is_usb_device(dev)) {
usb_dev = to_usb_device(dev);
else {
} else if (is_usb_interface(dev)) {
struct usb_interface *intf = to_usb_interface(dev);
usb_dev = interface_to_usbdev(intf);
} else {
return 0;
}
if (usb_dev->devnum < 0) {
@ -1762,6 +1750,7 @@ int usb_suspend(struct device *dev, pm_message_t msg)
int usb_resume(struct device *dev, pm_message_t msg)
{
struct usb_device *udev;
int status;
udev = to_usb_device(dev);
@ -1771,7 +1760,14 @@ int usb_resume(struct device *dev, pm_message_t msg)
*/
if (udev->skip_sys_resume)
return 0;
return usb_external_resume_device(udev, msg);
status = usb_external_resume_device(udev, msg);
/* Avoid PM error messages for devices disconnected while suspended
* as we'll display regular disconnect messages just a bit later.
*/
if (status == -ENODEV)
return 0;
return status;
}
#endif /* CONFIG_PM */

View File

@ -15,19 +15,18 @@
#include <linux/usb.h>
#include "usb.h"
#define MAX_ENDPOINT_MINORS (64*128*32)
static int usb_endpoint_major;
static DEFINE_IDR(endpoint_idr);
struct ep_device {
struct usb_endpoint_descriptor *desc;
struct usb_device *udev;
struct device dev;
int minor;
};
#define to_ep_device(_dev) \
container_of(_dev, struct ep_device, dev)
struct device_type usb_ep_device_type = {
.name = "usb_endpoint",
};
struct ep_attribute {
struct attribute attr;
ssize_t (*show)(struct usb_device *,
@ -160,118 +159,10 @@ static struct attribute_group *ep_dev_groups[] = {
NULL
};
static int usb_endpoint_major_init(void)
{
dev_t dev;
int error;
error = alloc_chrdev_region(&dev, 0, MAX_ENDPOINT_MINORS,
"usb_endpoint");
if (error) {
printk(KERN_ERR "Unable to get a dynamic major for "
"usb endpoints.\n");
return error;
}
usb_endpoint_major = MAJOR(dev);
return error;
}
static void usb_endpoint_major_cleanup(void)
{
unregister_chrdev_region(MKDEV(usb_endpoint_major, 0),
MAX_ENDPOINT_MINORS);
}
static int endpoint_get_minor(struct ep_device *ep_dev)
{
static DEFINE_MUTEX(minor_lock);
int retval = -ENOMEM;
int id;
mutex_lock(&minor_lock);
if (idr_pre_get(&endpoint_idr, GFP_KERNEL) == 0)
goto exit;
retval = idr_get_new(&endpoint_idr, ep_dev, &id);
if (retval < 0) {
if (retval == -EAGAIN)
retval = -ENOMEM;
goto exit;
}
ep_dev->minor = id & MAX_ID_MASK;
exit:
mutex_unlock(&minor_lock);
return retval;
}
static void endpoint_free_minor(struct ep_device *ep_dev)
{
idr_remove(&endpoint_idr, ep_dev->minor);
}
static struct endpoint_class {
struct kref kref;
struct class *class;
} *ep_class;
static int init_endpoint_class(void)
{
int result = 0;
if (ep_class != NULL) {
kref_get(&ep_class->kref);
goto exit;
}
ep_class = kmalloc(sizeof(*ep_class), GFP_KERNEL);
if (!ep_class) {
result = -ENOMEM;
goto exit;
}
kref_init(&ep_class->kref);
ep_class->class = class_create(THIS_MODULE, "usb_endpoint");
if (IS_ERR(ep_class->class)) {
result = PTR_ERR(ep_class->class);
goto class_create_error;
}
result = usb_endpoint_major_init();
if (result)
goto endpoint_major_error;
goto exit;
endpoint_major_error:
class_destroy(ep_class->class);
class_create_error:
kfree(ep_class);
ep_class = NULL;
exit:
return result;
}
static void release_endpoint_class(struct kref *kref)
{
/* Ok, we cheat as we know we only have one ep_class */
class_destroy(ep_class->class);
kfree(ep_class);
ep_class = NULL;
usb_endpoint_major_cleanup();
}
static void destroy_endpoint_class(void)
{
if (ep_class)
kref_put(&ep_class->kref, release_endpoint_class);
}
static void ep_device_release(struct device *dev)
{
struct ep_device *ep_dev = to_ep_device(dev);
endpoint_free_minor(ep_dev);
kfree(ep_dev);
}
@ -279,62 +170,32 @@ int usb_create_ep_devs(struct device *parent,
struct usb_host_endpoint *endpoint,
struct usb_device *udev)
{
char name[8];
struct ep_device *ep_dev;
int retval;
retval = init_endpoint_class();
if (retval)
goto exit;
ep_dev = kzalloc(sizeof(*ep_dev), GFP_KERNEL);
if (!ep_dev) {
retval = -ENOMEM;
goto error_alloc;
}
retval = endpoint_get_minor(ep_dev);
if (retval) {
dev_err(parent, "can not allocate minor number for %s\n",
dev_name(&ep_dev->dev));
goto error_register;
goto exit;
}
ep_dev->desc = &endpoint->desc;
ep_dev->udev = udev;
ep_dev->dev.groups = ep_dev_groups;
ep_dev->dev.devt = MKDEV(usb_endpoint_major, ep_dev->minor);
ep_dev->dev.class = ep_class->class;
ep_dev->dev.type = &usb_ep_device_type;
ep_dev->dev.parent = parent;
ep_dev->dev.release = ep_device_release;
dev_set_name(&ep_dev->dev, "usbdev%d.%d_ep%02x",
udev->bus->busnum, udev->devnum,
endpoint->desc.bEndpointAddress);
dev_set_name(&ep_dev->dev, "ep_%02x", endpoint->desc.bEndpointAddress);
retval = device_register(&ep_dev->dev);
if (retval)
goto error_chrdev;
goto error_register;
/* create the symlink to the old-style "ep_XX" directory */
sprintf(name, "ep_%02x", endpoint->desc.bEndpointAddress);
retval = sysfs_create_link(&parent->kobj, &ep_dev->dev.kobj, name);
if (retval)
goto error_link;
endpoint->ep_dev = ep_dev;
return retval;
error_link:
device_unregister(&ep_dev->dev);
destroy_endpoint_class();
return retval;
error_chrdev:
endpoint_free_minor(ep_dev);
error_register:
kfree(ep_dev);
error_alloc:
destroy_endpoint_class();
exit:
return retval;
}
@ -344,12 +205,7 @@ void usb_remove_ep_devs(struct usb_host_endpoint *endpoint)
struct ep_device *ep_dev = endpoint->ep_dev;
if (ep_dev) {
char name[8];
sprintf(name, "ep_%02x", endpoint->desc.bEndpointAddress);
sysfs_remove_link(&ep_dev->dev.parent->kobj, name);
device_unregister(&ep_dev->dev);
endpoint->ep_dev = NULL;
destroy_endpoint_class();
}
}

View File

@ -185,180 +185,6 @@ void usb_hcd_pci_remove(struct pci_dev *dev)
}
EXPORT_SYMBOL_GPL(usb_hcd_pci_remove);
#ifdef CONFIG_PM
/**
* usb_hcd_pci_suspend - power management suspend of a PCI-based HCD
* @dev: USB Host Controller being suspended
* @message: Power Management message describing this state transition
*
* Store this function in the HCD's struct pci_driver as .suspend.
*/
int usb_hcd_pci_suspend(struct pci_dev *dev, pm_message_t message)
{
struct usb_hcd *hcd = pci_get_drvdata(dev);
int retval = 0;
int wake, w;
int has_pci_pm;
/* Root hub suspend should have stopped all downstream traffic,
* and all bus master traffic. And done so for both the interface
* and the stub usb_device (which we check here). But maybe it
* didn't; writing sysfs power/state files ignores such rules...
*
* We must ignore the FREEZE vs SUSPEND distinction here, because
* otherwise the swsusp will save (and restore) garbage state.
*/
if (!(hcd->state == HC_STATE_SUSPENDED ||
hcd->state == HC_STATE_HALT)) {
dev_warn(&dev->dev, "Root hub is not suspended\n");
retval = -EBUSY;
goto done;
}
/* We might already be suspended (runtime PM -- not yet written) */
if (dev->current_state != PCI_D0)
goto done;
if (hcd->driver->pci_suspend) {
retval = hcd->driver->pci_suspend(hcd, message);
suspend_report_result(hcd->driver->pci_suspend, retval);
if (retval)
goto done;
}
synchronize_irq(dev->irq);
/* Downstream ports from this root hub should already be quiesced, so
* there will be no DMA activity. Now we can shut down the upstream
* link (except maybe for PME# resume signaling) and enter some PCI
* low power state, if the hardware allows.
*/
pci_disable_device(dev);
pci_save_state(dev);
/* Don't fail on error to enable wakeup. We rely on pci code
* to reject requests the hardware can't implement, rather
* than coding the same thing.
*/
wake = (hcd->state == HC_STATE_SUSPENDED &&
device_may_wakeup(&dev->dev));
w = pci_wake_from_d3(dev, wake);
if (w < 0)
wake = w;
dev_dbg(&dev->dev, "wakeup: %d\n", wake);
/* Don't change state if we don't need to */
if (message.event == PM_EVENT_FREEZE ||
message.event == PM_EVENT_PRETHAW) {
dev_dbg(&dev->dev, "--> no state change\n");
goto done;
}
has_pci_pm = pci_find_capability(dev, PCI_CAP_ID_PM);
if (!has_pci_pm) {
dev_dbg(&dev->dev, "--> PCI D0 legacy\n");
} else {
/* NOTE: dev->current_state becomes nonzero only here, and
* only for devices that support PCI PM. Also, exiting
* PCI_D3 (but not PCI_D1 or PCI_D2) is allowed to reset
* some device state (e.g. as part of clock reinit).
*/
retval = pci_set_power_state(dev, PCI_D3hot);
suspend_report_result(pci_set_power_state, retval);
if (retval == 0) {
dev_dbg(&dev->dev, "--> PCI D3\n");
} else {
dev_dbg(&dev->dev, "PCI D3 suspend fail, %d\n",
retval);
pci_restore_state(dev);
}
}
#ifdef CONFIG_PPC_PMAC
if (retval == 0) {
/* Disable ASIC clocks for USB */
if (machine_is(powermac)) {
struct device_node *of_node;
of_node = pci_device_to_OF_node(dev);
if (of_node)
pmac_call_feature(PMAC_FTR_USB_ENABLE,
of_node, 0, 0);
}
}
#endif
done:
return retval;
}
EXPORT_SYMBOL_GPL(usb_hcd_pci_suspend);
/**
* usb_hcd_pci_resume - power management resume of a PCI-based HCD
* @dev: USB Host Controller being resumed
*
* Store this function in the HCD's struct pci_driver as .resume.
*/
int usb_hcd_pci_resume(struct pci_dev *dev)
{
struct usb_hcd *hcd;
int retval;
#ifdef CONFIG_PPC_PMAC
/* Reenable ASIC clocks for USB */
if (machine_is(powermac)) {
struct device_node *of_node;
of_node = pci_device_to_OF_node(dev);
if (of_node)
pmac_call_feature(PMAC_FTR_USB_ENABLE,
of_node, 0, 1);
}
#endif
pci_restore_state(dev);
hcd = pci_get_drvdata(dev);
if (hcd->state != HC_STATE_SUSPENDED) {
dev_dbg(hcd->self.controller,
"can't resume, not suspended!\n");
return 0;
}
pci_enable_wake(dev, PCI_D0, false);
retval = pci_enable_device(dev);
if (retval < 0) {
dev_err(&dev->dev, "can't re-enable after resume, %d!\n",
retval);
return retval;
}
pci_set_master(dev);
/* yes, ignore this result too... */
(void) pci_wake_from_d3(dev, 0);
clear_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
if (hcd->driver->pci_resume) {
retval = hcd->driver->pci_resume(hcd);
if (retval) {
dev_err(hcd->self.controller,
"PCI post-resume error %d!\n", retval);
usb_hc_died(hcd);
}
}
return retval;
}
EXPORT_SYMBOL_GPL(usb_hcd_pci_resume);
#endif /* CONFIG_PM */
/**
* usb_hcd_pci_shutdown - shutdown host controller
* @dev: USB Host Controller being shutdown
@ -376,3 +202,181 @@ void usb_hcd_pci_shutdown(struct pci_dev *dev)
}
EXPORT_SYMBOL_GPL(usb_hcd_pci_shutdown);
#ifdef CONFIG_PM_SLEEP
static int check_root_hub_suspended(struct device *dev)
{
struct pci_dev *pci_dev = to_pci_dev(dev);
struct usb_hcd *hcd = pci_get_drvdata(pci_dev);
if (!(hcd->state == HC_STATE_SUSPENDED ||
hcd->state == HC_STATE_HALT)) {
dev_warn(dev, "Root hub is not suspended\n");
return -EBUSY;
}
return 0;
}
static int hcd_pci_suspend(struct device *dev)
{
struct pci_dev *pci_dev = to_pci_dev(dev);
struct usb_hcd *hcd = pci_get_drvdata(pci_dev);
int retval;
/* Root hub suspend should have stopped all downstream traffic,
* and all bus master traffic. And done so for both the interface
* and the stub usb_device (which we check here). But maybe it
* didn't; writing sysfs power/state files ignores such rules...
*/
retval = check_root_hub_suspended(dev);
if (retval)
return retval;
/* We might already be suspended (runtime PM -- not yet written) */
if (pci_dev->current_state != PCI_D0)
return retval;
if (hcd->driver->pci_suspend) {
retval = hcd->driver->pci_suspend(hcd);
suspend_report_result(hcd->driver->pci_suspend, retval);
if (retval)
return retval;
}
synchronize_irq(pci_dev->irq);
/* Downstream ports from this root hub should already be quiesced, so
* there will be no DMA activity. Now we can shut down the upstream
* link (except maybe for PME# resume signaling). We'll enter a
* low power state during suspend_noirq, if the hardware allows.
*/
pci_disable_device(pci_dev);
return retval;
}
static int hcd_pci_suspend_noirq(struct device *dev)
{
struct pci_dev *pci_dev = to_pci_dev(dev);
struct usb_hcd *hcd = pci_get_drvdata(pci_dev);
int retval;
retval = check_root_hub_suspended(dev);
if (retval)
return retval;
pci_save_state(pci_dev);
/* If the root hub is HALTed rather than SUSPENDed,
* disallow remote wakeup.
*/
if (hcd->state == HC_STATE_HALT)
device_set_wakeup_enable(dev, 0);
dev_dbg(dev, "wakeup: %d\n", device_may_wakeup(dev));
/* Possibly enable remote wakeup,
* choose the appropriate low-power state, and go to that state.
*/
retval = pci_prepare_to_sleep(pci_dev);
if (retval == -EIO) { /* Low-power not supported */
dev_dbg(dev, "--> PCI D0 legacy\n");
retval = 0;
} else if (retval == 0) {
dev_dbg(dev, "--> PCI %s\n",
pci_power_name(pci_dev->current_state));
} else {
suspend_report_result(pci_prepare_to_sleep, retval);
return retval;
}
#ifdef CONFIG_PPC_PMAC
/* Disable ASIC clocks for USB */
if (machine_is(powermac)) {
struct device_node *of_node;
of_node = pci_device_to_OF_node(pci_dev);
if (of_node)
pmac_call_feature(PMAC_FTR_USB_ENABLE, of_node, 0, 0);
}
#endif
return retval;
}
static int hcd_pci_resume_noirq(struct device *dev)
{
struct pci_dev *pci_dev = to_pci_dev(dev);
#ifdef CONFIG_PPC_PMAC
/* Reenable ASIC clocks for USB */
if (machine_is(powermac)) {
struct device_node *of_node;
of_node = pci_device_to_OF_node(pci_dev);
if (of_node)
pmac_call_feature(PMAC_FTR_USB_ENABLE,
of_node, 0, 1);
}
#endif
/* Go back to D0 and disable remote wakeup */
pci_back_from_sleep(pci_dev);
return 0;
}
static int resume_common(struct device *dev, bool hibernated)
{
struct pci_dev *pci_dev = to_pci_dev(dev);
struct usb_hcd *hcd = pci_get_drvdata(pci_dev);
int retval;
if (hcd->state != HC_STATE_SUSPENDED) {
dev_dbg(dev, "can't resume, not suspended!\n");
return 0;
}
retval = pci_enable_device(pci_dev);
if (retval < 0) {
dev_err(dev, "can't re-enable after resume, %d!\n", retval);
return retval;
}
pci_set_master(pci_dev);
clear_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
if (hcd->driver->pci_resume) {
retval = hcd->driver->pci_resume(hcd, hibernated);
if (retval) {
dev_err(dev, "PCI post-resume error %d!\n", retval);
usb_hc_died(hcd);
}
}
return retval;
}
static int hcd_pci_resume(struct device *dev)
{
return resume_common(dev, false);
}
static int hcd_pci_restore(struct device *dev)
{
return resume_common(dev, true);
}
struct dev_pm_ops usb_hcd_pci_pm_ops = {
.suspend = hcd_pci_suspend,
.suspend_noirq = hcd_pci_suspend_noirq,
.resume_noirq = hcd_pci_resume_noirq,
.resume = hcd_pci_resume,
.freeze = check_root_hub_suspended,
.freeze_noirq = check_root_hub_suspended,
.thaw_noirq = NULL,
.thaw = NULL,
.poweroff = hcd_pci_suspend,
.poweroff_noirq = hcd_pci_suspend_noirq,
.restore_noirq = hcd_pci_resume_noirq,
.restore = hcd_pci_restore,
};
EXPORT_SYMBOL_GPL(usb_hcd_pci_pm_ops);
#endif /* CONFIG_PM_SLEEP */

View File

@ -128,6 +128,27 @@ static inline int is_root_hub(struct usb_device *udev)
#define KERNEL_REL ((LINUX_VERSION_CODE >> 16) & 0x0ff)
#define KERNEL_VER ((LINUX_VERSION_CODE >> 8) & 0x0ff)
/* usb 3.0 root hub device descriptor */
static const u8 usb3_rh_dev_descriptor[18] = {
0x12, /* __u8 bLength; */
0x01, /* __u8 bDescriptorType; Device */
0x00, 0x03, /* __le16 bcdUSB; v3.0 */
0x09, /* __u8 bDeviceClass; HUB_CLASSCODE */
0x00, /* __u8 bDeviceSubClass; */
0x03, /* __u8 bDeviceProtocol; USB 3.0 hub */
0x09, /* __u8 bMaxPacketSize0; 2^9 = 512 Bytes */
0x6b, 0x1d, /* __le16 idVendor; Linux Foundation */
0x02, 0x00, /* __le16 idProduct; device 0x0002 */
KERNEL_VER, KERNEL_REL, /* __le16 bcdDevice */
0x03, /* __u8 iManufacturer; */
0x02, /* __u8 iProduct; */
0x01, /* __u8 iSerialNumber; */
0x01 /* __u8 bNumConfigurations; */
};
/* usb 2.0 root hub device descriptor */
static const u8 usb2_rh_dev_descriptor [18] = {
0x12, /* __u8 bLength; */
@ -273,6 +294,47 @@ static const u8 hs_rh_config_descriptor [] = {
0x0c /* __u8 ep_bInterval; (256ms -- usb 2.0 spec) */
};
static const u8 ss_rh_config_descriptor[] = {
/* one configuration */
0x09, /* __u8 bLength; */
0x02, /* __u8 bDescriptorType; Configuration */
0x19, 0x00, /* __le16 wTotalLength; FIXME */
0x01, /* __u8 bNumInterfaces; (1) */
0x01, /* __u8 bConfigurationValue; */
0x00, /* __u8 iConfiguration; */
0xc0, /* __u8 bmAttributes;
Bit 7: must be set,
6: Self-powered,
5: Remote wakeup,
4..0: resvd */
0x00, /* __u8 MaxPower; */
/* one interface */
0x09, /* __u8 if_bLength; */
0x04, /* __u8 if_bDescriptorType; Interface */
0x00, /* __u8 if_bInterfaceNumber; */
0x00, /* __u8 if_bAlternateSetting; */
0x01, /* __u8 if_bNumEndpoints; */
0x09, /* __u8 if_bInterfaceClass; HUB_CLASSCODE */
0x00, /* __u8 if_bInterfaceSubClass; */
0x00, /* __u8 if_bInterfaceProtocol; */
0x00, /* __u8 if_iInterface; */
/* one endpoint (status change endpoint) */
0x07, /* __u8 ep_bLength; */
0x05, /* __u8 ep_bDescriptorType; Endpoint */
0x81, /* __u8 ep_bEndpointAddress; IN Endpoint 1 */
0x03, /* __u8 ep_bmAttributes; Interrupt */
/* __le16 ep_wMaxPacketSize; 1 + (MAX_ROOT_PORTS / 8)
* see hub.c:hub_configure() for details. */
(USB_MAXCHILDREN + 1 + 7) / 8, 0x00,
0x0c /* __u8 ep_bInterval; (256ms -- usb 2.0 spec) */
/*
* All 3.0 hubs should have an endpoint companion descriptor,
* but we're ignoring that for now. FIXME?
*/
};
/*-------------------------------------------------------------------------*/
/*
@ -426,23 +488,39 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
switch (wValue & 0xff00) {
case USB_DT_DEVICE << 8:
if (hcd->driver->flags & HCD_USB2)
switch (hcd->driver->flags & HCD_MASK) {
case HCD_USB3:
bufp = usb3_rh_dev_descriptor;
break;
case HCD_USB2:
bufp = usb2_rh_dev_descriptor;
else if (hcd->driver->flags & HCD_USB11)
break;
case HCD_USB11:
bufp = usb11_rh_dev_descriptor;
else
break;
default:
goto error;
}
len = 18;
if (hcd->has_tt)
patch_protocol = 1;
break;
case USB_DT_CONFIG << 8:
if (hcd->driver->flags & HCD_USB2) {
switch (hcd->driver->flags & HCD_MASK) {
case HCD_USB3:
bufp = ss_rh_config_descriptor;
len = sizeof ss_rh_config_descriptor;
break;
case HCD_USB2:
bufp = hs_rh_config_descriptor;
len = sizeof hs_rh_config_descriptor;
} else {
break;
case HCD_USB11:
bufp = fs_rh_config_descriptor;
len = sizeof fs_rh_config_descriptor;
break;
default:
goto error;
}
if (device_can_wakeup(&hcd->self.root_hub->dev))
patch_wakeup = 1;
@ -755,23 +833,6 @@ static struct attribute_group usb_bus_attr_group = {
/*-------------------------------------------------------------------------*/
static struct class *usb_host_class;
int usb_host_init(void)
{
int retval = 0;
usb_host_class = class_create(THIS_MODULE, "usb_host");
if (IS_ERR(usb_host_class))
retval = PTR_ERR(usb_host_class);
return retval;
}
void usb_host_cleanup(void)
{
class_destroy(usb_host_class);
}
/**
* usb_bus_init - shared initialization code
* @bus: the bus structure being initialized
@ -818,12 +879,6 @@ static int usb_register_bus(struct usb_bus *bus)
set_bit (busnum, busmap.busmap);
bus->busnum = busnum;
bus->dev = device_create(usb_host_class, bus->controller, MKDEV(0, 0),
bus, "usb_host%d", busnum);
result = PTR_ERR(bus->dev);
if (IS_ERR(bus->dev))
goto error_create_class_dev;
/* Add it to the local list of buses */
list_add (&bus->bus_list, &usb_bus_list);
mutex_unlock(&usb_bus_list_lock);
@ -834,8 +889,6 @@ static int usb_register_bus(struct usb_bus *bus)
"number %d\n", bus->busnum);
return 0;
error_create_class_dev:
clear_bit(busnum, busmap.busmap);
error_find_busnum:
mutex_unlock(&usb_bus_list_lock);
return result;
@ -865,8 +918,6 @@ static void usb_deregister_bus (struct usb_bus *bus)
usb_notify_remove_bus(bus);
clear_bit (bus->busnum, busmap.busmap);
device_unregister(bus->dev);
}
/**
@ -1199,7 +1250,8 @@ static int map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
/* Map the URB's buffers for DMA access.
* Lower level HCD code should use *_dma exclusively,
* unless it uses pio or talks to another transport.
* unless it uses pio or talks to another transport,
* or uses the provided scatter gather list for bulk.
*/
if (is_root_hub(urb->dev))
return 0;
@ -1520,6 +1572,92 @@ rescan:
}
}
/* Check whether a new configuration or alt setting for an interface
* will exceed the bandwidth for the bus (or the host controller resources).
* Only pass in a non-NULL config or interface, not both!
* Passing NULL for both new_config and new_intf means the device will be
* de-configured by issuing a set configuration 0 command.
*/
int usb_hcd_check_bandwidth(struct usb_device *udev,
struct usb_host_config *new_config,
struct usb_interface *new_intf)
{
int num_intfs, i, j;
struct usb_interface_cache *intf_cache;
struct usb_host_interface *alt = 0;
int ret = 0;
struct usb_hcd *hcd;
struct usb_host_endpoint *ep;
hcd = bus_to_hcd(udev->bus);
if (!hcd->driver->check_bandwidth)
return 0;
/* Configuration is being removed - set configuration 0 */
if (!new_config && !new_intf) {
for (i = 1; i < 16; ++i) {
ep = udev->ep_out[i];
if (ep)
hcd->driver->drop_endpoint(hcd, udev, ep);
ep = udev->ep_in[i];
if (ep)
hcd->driver->drop_endpoint(hcd, udev, ep);
}
hcd->driver->check_bandwidth(hcd, udev);
return 0;
}
/* Check if the HCD says there's enough bandwidth. Enable all endpoints
* each interface's alt setting 0 and ask the HCD to check the bandwidth
* of the bus. There will always be bandwidth for endpoint 0, so it's
* ok to exclude it.
*/
if (new_config) {
num_intfs = new_config->desc.bNumInterfaces;
/* Remove endpoints (except endpoint 0, which is always on the
* schedule) from the old config from the schedule
*/
for (i = 1; i < 16; ++i) {
ep = udev->ep_out[i];
if (ep) {
ret = hcd->driver->drop_endpoint(hcd, udev, ep);
if (ret < 0)
goto reset;
}
ep = udev->ep_in[i];
if (ep) {
ret = hcd->driver->drop_endpoint(hcd, udev, ep);
if (ret < 0)
goto reset;
}
}
for (i = 0; i < num_intfs; ++i) {
/* Dig the endpoints for alt setting 0 out of the
* interface cache for this interface
*/
intf_cache = new_config->intf_cache[i];
for (j = 0; j < intf_cache->num_altsetting; j++) {
if (intf_cache->altsetting[j].desc.bAlternateSetting == 0)
alt = &intf_cache->altsetting[j];
}
if (!alt) {
printk(KERN_DEBUG "Did not find alt setting 0 for intf %d\n", i);
continue;
}
for (j = 0; j < alt->desc.bNumEndpoints; j++) {
ret = hcd->driver->add_endpoint(hcd, udev, &alt->endpoint[j]);
if (ret < 0)
goto reset;
}
}
}
ret = hcd->driver->check_bandwidth(hcd, udev);
reset:
if (ret < 0)
hcd->driver->reset_bandwidth(hcd, udev);
return ret;
}
/* Disables the endpoint: synchronizes with the hcd to make sure all
* endpoint state is gone from hardware. usb_hcd_flush_endpoint() must
* have been called previously. Use for set_configuration, set_interface,
@ -1897,8 +2035,20 @@ int usb_add_hcd(struct usb_hcd *hcd,
retval = -ENOMEM;
goto err_allocate_root_hub;
}
rhdev->speed = (hcd->driver->flags & HCD_USB2) ? USB_SPEED_HIGH :
USB_SPEED_FULL;
switch (hcd->driver->flags & HCD_MASK) {
case HCD_USB11:
rhdev->speed = USB_SPEED_FULL;
break;
case HCD_USB2:
rhdev->speed = USB_SPEED_HIGH;
break;
case HCD_USB3:
rhdev->speed = USB_SPEED_SUPER;
break;
default:
goto err_allocate_root_hub;
}
hcd->self.root_hub = rhdev;
/* wakeup flag init defaults to "everything works" for root hubs,

View File

@ -173,6 +173,8 @@ struct hc_driver {
#define HCD_LOCAL_MEM 0x0002 /* HC needs local memory */
#define HCD_USB11 0x0010 /* USB 1.1 */
#define HCD_USB2 0x0020 /* USB 2.0 */
#define HCD_USB3 0x0040 /* USB 3.0 */
#define HCD_MASK 0x0070
/* called to init HCD and root hub */
int (*reset) (struct usb_hcd *hcd);
@ -182,10 +184,10 @@ struct hc_driver {
* a whole, not just the root hub; they're for PCI bus glue.
*/
/* called after suspending the hub, before entering D3 etc */
int (*pci_suspend) (struct usb_hcd *hcd, pm_message_t message);
int (*pci_suspend)(struct usb_hcd *hcd);
/* called after entering D0 (etc), before resuming the hub */
int (*pci_resume) (struct usb_hcd *hcd);
int (*pci_resume)(struct usb_hcd *hcd, bool hibernated);
/* cleanly make HCD stop writing memory and doing I/O */
void (*stop) (struct usb_hcd *hcd);
@ -224,6 +226,43 @@ struct hc_driver {
void (*relinquish_port)(struct usb_hcd *, int);
/* has a port been handed over to a companion? */
int (*port_handed_over)(struct usb_hcd *, int);
/* xHCI specific functions */
/* Called by usb_alloc_dev to alloc HC device structures */
int (*alloc_dev)(struct usb_hcd *, struct usb_device *);
/* Called by usb_release_dev to free HC device structures */
void (*free_dev)(struct usb_hcd *, struct usb_device *);
/* Bandwidth computation functions */
/* Note that add_endpoint() can only be called once per endpoint before
* check_bandwidth() or reset_bandwidth() must be called.
* drop_endpoint() can only be called once per endpoint also.
* A call to xhci_drop_endpoint() followed by a call to xhci_add_endpoint() will
* add the endpoint to the schedule with possibly new parameters denoted by a
* different endpoint descriptor in usb_host_endpoint.
* A call to xhci_add_endpoint() followed by a call to xhci_drop_endpoint() is
* not allowed.
*/
/* Allocate endpoint resources and add them to a new schedule */
int (*add_endpoint)(struct usb_hcd *, struct usb_device *, struct usb_host_endpoint *);
/* Drop an endpoint from a new schedule */
int (*drop_endpoint)(struct usb_hcd *, struct usb_device *, struct usb_host_endpoint *);
/* Check that a new hardware configuration, set using
* endpoint_enable and endpoint_disable, does not exceed bus
* bandwidth. This must be called before any set configuration
* or set interface requests are sent to the device.
*/
int (*check_bandwidth)(struct usb_hcd *, struct usb_device *);
/* Reset the device schedule to the last known good schedule,
* which was set from a previous successful call to
* check_bandwidth(). This reverts any add_endpoint() and
* drop_endpoint() calls since that last successful call.
* Used for when a check_bandwidth() call fails due to resource
* or bandwidth constraints.
*/
void (*reset_bandwidth)(struct usb_hcd *, struct usb_device *);
/* Returns the hardware-chosen device address */
int (*address_device)(struct usb_hcd *, struct usb_device *udev);
};
extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb);
@ -242,6 +281,9 @@ extern void usb_hcd_disable_endpoint(struct usb_device *udev,
extern void usb_hcd_reset_endpoint(struct usb_device *udev,
struct usb_host_endpoint *ep);
extern void usb_hcd_synchronize_unlinks(struct usb_device *udev);
extern int usb_hcd_check_bandwidth(struct usb_device *udev,
struct usb_host_config *new_config,
struct usb_interface *new_intf);
extern int usb_hcd_get_frame_number(struct usb_device *udev);
extern struct usb_hcd *usb_create_hcd(const struct hc_driver *driver,
@ -261,14 +303,11 @@ struct pci_device_id;
extern int usb_hcd_pci_probe(struct pci_dev *dev,
const struct pci_device_id *id);
extern void usb_hcd_pci_remove(struct pci_dev *dev);
#ifdef CONFIG_PM
extern int usb_hcd_pci_suspend(struct pci_dev *dev, pm_message_t msg);
extern int usb_hcd_pci_resume(struct pci_dev *dev);
#endif /* CONFIG_PM */
extern void usb_hcd_pci_shutdown(struct pci_dev *dev);
#ifdef CONFIG_PM_SLEEP
extern struct dev_pm_ops usb_hcd_pci_pm_ops;
#endif
#endif /* CONFIG_PCI */
/* pci-ish (pdev null is ok) buffer alloc/mapping support */

View File

@ -155,6 +155,8 @@ static inline char *portspeed(int portstatus)
return "480 Mb/s";
else if (portstatus & (1 << USB_PORT_FEAT_LOWSPEED))
return "1.5 Mb/s";
else if (portstatus & (1 << USB_PORT_FEAT_SUPERSPEED))
return "5.0 Gb/s";
else
return "12 Mb/s";
}
@ -457,13 +459,13 @@ static void hub_tt_kevent (struct work_struct *work)
spin_lock_irqsave (&hub->tt.lock, flags);
while (--limit && !list_empty (&hub->tt.clear_list)) {
struct list_head *temp;
struct list_head *next;
struct usb_tt_clear *clear;
struct usb_device *hdev = hub->hdev;
int status;
temp = hub->tt.clear_list.next;
clear = list_entry (temp, struct usb_tt_clear, clear_list);
next = hub->tt.clear_list.next;
clear = list_entry (next, struct usb_tt_clear, clear_list);
list_del (&clear->clear_list);
/* drop lock so HCD can concurrently report other TT errors */
@ -951,6 +953,9 @@ static int hub_configure(struct usb_hub *hub,
ret);
hub->tt.hub = hdev;
break;
case 3:
/* USB 3.0 hubs don't have a TT */
break;
default:
dev_dbg(hub_dev, "Unrecognized hub protocol %d\n",
hdev->descriptor.bDeviceProtocol);
@ -1323,6 +1328,11 @@ EXPORT_SYMBOL_GPL(usb_set_device_state);
* 0 is reserved by USB for default address; (b) Linux's USB stack
* uses always #1 for the root hub of the controller. So USB stack's
* port #1, which is wusb virtual-port #0 has address #2.
*
* Devices connected under xHCI are not as simple. The host controller
* supports virtualization, so the hardware assigns device addresses and
* the HCD must setup data structures before issuing a set address
* command to the hardware.
*/
static void choose_address(struct usb_device *udev)
{
@ -1642,6 +1652,9 @@ int usb_new_device(struct usb_device *udev)
err = usb_configure_device(udev); /* detect & probe dev/intfs */
if (err < 0)
goto fail;
dev_dbg(&udev->dev, "udev %d, busnum %d, minor = %d\n",
udev->devnum, udev->bus->busnum,
(((udev->bus->busnum-1) * 128) + (udev->devnum-1)));
/* export the usbdev device-node for libusb */
udev->dev.devt = MKDEV(USB_DEVICE_MAJOR,
(((udev->bus->busnum-1) * 128) + (udev->devnum-1)));
@ -2395,19 +2408,29 @@ EXPORT_SYMBOL_GPL(usb_ep0_reinit);
static int hub_set_address(struct usb_device *udev, int devnum)
{
int retval;
struct usb_hcd *hcd = bus_to_hcd(udev->bus);
if (devnum <= 1)
/*
* The host controller will choose the device address,
* instead of the core having chosen it earlier
*/
if (!hcd->driver->address_device && devnum <= 1)
return -EINVAL;
if (udev->state == USB_STATE_ADDRESS)
return 0;
if (udev->state != USB_STATE_DEFAULT)
return -EINVAL;
retval = usb_control_msg(udev, usb_sndaddr0pipe(),
USB_REQ_SET_ADDRESS, 0, devnum, 0,
NULL, 0, USB_CTRL_SET_TIMEOUT);
if (hcd->driver->address_device) {
retval = hcd->driver->address_device(hcd, udev);
} else {
retval = usb_control_msg(udev, usb_sndaddr0pipe(),
USB_REQ_SET_ADDRESS, 0, devnum, 0,
NULL, 0, USB_CTRL_SET_TIMEOUT);
if (retval == 0)
update_address(udev, devnum);
}
if (retval == 0) {
/* Device now using proper address. */
update_address(udev, devnum);
usb_set_device_state(udev, USB_STATE_ADDRESS);
usb_ep0_reinit(udev);
}
@ -2430,6 +2453,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
static DEFINE_MUTEX(usb_address0_mutex);
struct usb_device *hdev = hub->hdev;
struct usb_hcd *hcd = bus_to_hcd(hdev->bus);
int i, j, retval;
unsigned delay = HUB_SHORT_RESET_TIME;
enum usb_device_speed oldspeed = udev->speed;
@ -2452,11 +2476,24 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
mutex_lock(&usb_address0_mutex);
/* Reset the device; full speed may morph to high speed */
retval = hub_port_reset(hub, port1, udev, delay);
if (retval < 0) /* error or disconnect */
if ((hcd->driver->flags & HCD_USB3) && udev->config) {
/* FIXME this will need special handling by the xHCI driver. */
dev_dbg(&udev->dev,
"xHCI reset of configured device "
"not supported yet.\n");
retval = -EINVAL;
goto fail;
/* success, speed is known */
} else if (!udev->config && oldspeed == USB_SPEED_SUPER) {
/* Don't reset USB 3.0 devices during an initial setup */
usb_set_device_state(udev, USB_STATE_DEFAULT);
} else {
/* Reset the device; full speed may morph to high speed */
/* FIXME a USB 2.0 device may morph into SuperSpeed on reset. */
retval = hub_port_reset(hub, port1, udev, delay);
if (retval < 0) /* error or disconnect */
goto fail;
/* success, speed is known */
}
retval = -ENODEV;
if (oldspeed != USB_SPEED_UNKNOWN && oldspeed != udev->speed) {
@ -2471,6 +2508,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
* reported as 0xff in the device descriptor). WUSB1.0[4.8.1].
*/
switch (udev->speed) {
case USB_SPEED_SUPER:
case USB_SPEED_VARIABLE: /* fixed at 512 */
udev->ep0.desc.wMaxPacketSize = cpu_to_le16(512);
break;
@ -2496,16 +2534,20 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
case USB_SPEED_LOW: speed = "low"; break;
case USB_SPEED_FULL: speed = "full"; break;
case USB_SPEED_HIGH: speed = "high"; break;
case USB_SPEED_SUPER:
speed = "super";
break;
case USB_SPEED_VARIABLE:
speed = "variable";
type = "Wireless ";
break;
default: speed = "?"; break;
}
dev_info (&udev->dev,
"%s %s speed %sUSB device using %s and address %d\n",
(udev->config) ? "reset" : "new", speed, type,
udev->bus->controller->driver->name, devnum);
if (udev->speed != USB_SPEED_SUPER)
dev_info(&udev->dev,
"%s %s speed %sUSB device using %s and address %d\n",
(udev->config) ? "reset" : "new", speed, type,
udev->bus->controller->driver->name, devnum);
/* Set up TT records, if needed */
if (hdev->tt) {
@ -2530,7 +2572,11 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
* value.
*/
for (i = 0; i < GET_DESCRIPTOR_TRIES; (++i, msleep(100))) {
if (USE_NEW_SCHEME(retry_counter)) {
/*
* An xHCI controller cannot send any packets to a device until
* a set address command successfully completes.
*/
if (USE_NEW_SCHEME(retry_counter) && !(hcd->driver->flags & HCD_USB3)) {
struct usb_device_descriptor *buf;
int r = 0;
@ -2596,7 +2642,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
* unauthorized address in the Connect Ack sequence;
* authorization will assign the final address.
*/
if (udev->wusb == 0) {
if (udev->wusb == 0) {
for (j = 0; j < SET_ADDRESS_TRIES; ++j) {
retval = hub_set_address(udev, devnum);
if (retval >= 0)
@ -2609,13 +2655,20 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
devnum, retval);
goto fail;
}
if (udev->speed == USB_SPEED_SUPER) {
devnum = udev->devnum;
dev_info(&udev->dev,
"%s SuperSpeed USB device using %s and address %d\n",
(udev->config) ? "reset" : "new",
udev->bus->controller->driver->name, devnum);
}
/* cope with hardware quirkiness:
* - let SET_ADDRESS settle, some device hardware wants it
* - read ep0 maxpacket even for high and low speed,
*/
msleep(10);
if (USE_NEW_SCHEME(retry_counter))
if (USE_NEW_SCHEME(retry_counter) && !(hcd->driver->flags & HCD_USB3))
break;
}
@ -2634,8 +2687,11 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
if (retval)
goto fail;
i = udev->descriptor.bMaxPacketSize0 == 0xff? /* wusb device? */
512 : udev->descriptor.bMaxPacketSize0;
if (udev->descriptor.bMaxPacketSize0 == 0xff ||
udev->speed == USB_SPEED_SUPER)
i = 512;
else
i = udev->descriptor.bMaxPacketSize0;
if (le16_to_cpu(udev->ep0.desc.wMaxPacketSize) != i) {
if (udev->speed != USB_SPEED_FULL ||
!(i == 8 || i == 16 || i == 32 || i == 64)) {
@ -2847,19 +2903,41 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
}
usb_set_device_state(udev, USB_STATE_POWERED);
udev->speed = USB_SPEED_UNKNOWN;
udev->bus_mA = hub->mA_per_port;
udev->level = hdev->level + 1;
udev->wusb = hub_is_wusb(hub);
/* set the address */
choose_address(udev);
if (udev->devnum <= 0) {
status = -ENOTCONN; /* Don't retry */
goto loop;
/*
* USB 3.0 devices are reset automatically before the connect
* port status change appears, and the root hub port status
* shows the correct speed. We also get port change
* notifications for USB 3.0 devices from the USB 3.0 portion of
* an external USB 3.0 hub, but this isn't handled correctly yet
* FIXME.
*/
if (!(hcd->driver->flags & HCD_USB3))
udev->speed = USB_SPEED_UNKNOWN;
else if ((hdev->parent == NULL) &&
(portstatus & (1 << USB_PORT_FEAT_SUPERSPEED)))
udev->speed = USB_SPEED_SUPER;
else
udev->speed = USB_SPEED_UNKNOWN;
/*
* xHCI needs to issue an address device command later
* in the hub_port_init sequence for SS/HS/FS/LS devices.
*/
if (!(hcd->driver->flags & HCD_USB3)) {
/* set the address */
choose_address(udev);
if (udev->devnum <= 0) {
status = -ENOTCONN; /* Don't retry */
goto loop;
}
}
/* reset and get descriptor */
/* reset (non-USB 3.0 devices) and get descriptor */
status = hub_port_init(hub, udev, port1, i);
if (status < 0)
goto loop;

View File

@ -47,7 +47,10 @@
#define USB_PORT_FEAT_L1 5 /* L1 suspend */
#define USB_PORT_FEAT_POWER 8
#define USB_PORT_FEAT_LOWSPEED 9
/* This value was never in Table 11-17 */
#define USB_PORT_FEAT_HIGHSPEED 10
/* This value is also fake */
#define USB_PORT_FEAT_SUPERSPEED 11
#define USB_PORT_FEAT_C_CONNECTION 16
#define USB_PORT_FEAT_C_ENABLE 17
#define USB_PORT_FEAT_C_SUSPEND 18

View File

@ -10,6 +10,7 @@
#include <linux/mm.h>
#include <linux/timer.h>
#include <linux/ctype.h>
#include <linux/nls.h>
#include <linux/device.h>
#include <linux/scatterlist.h>
#include <linux/usb/quirks.h>
@ -364,6 +365,7 @@ int usb_sg_init(struct usb_sg_request *io, struct usb_device *dev,
int i;
int urb_flags;
int dma;
int use_sg;
if (!io || !dev || !sg
|| usb_pipecontrol(pipe)
@ -391,7 +393,19 @@ int usb_sg_init(struct usb_sg_request *io, struct usb_device *dev,
if (io->entries <= 0)
return io->entries;
io->urbs = kmalloc(io->entries * sizeof *io->urbs, mem_flags);
/* If we're running on an xHCI host controller, queue the whole scatter
* gather list with one call to urb_enqueue(). This is only for bulk,
* as that endpoint type does not care how the data gets broken up
* across frames.
*/
if (usb_pipebulk(pipe) &&
bus_to_hcd(dev->bus)->driver->flags & HCD_USB3) {
io->urbs = kmalloc(sizeof *io->urbs, mem_flags);
use_sg = true;
} else {
io->urbs = kmalloc(io->entries * sizeof *io->urbs, mem_flags);
use_sg = false;
}
if (!io->urbs)
goto nomem;
@ -401,62 +415,92 @@ int usb_sg_init(struct usb_sg_request *io, struct usb_device *dev,
if (usb_pipein(pipe))
urb_flags |= URB_SHORT_NOT_OK;
for_each_sg(sg, sg, io->entries, i) {
unsigned len;
io->urbs[i] = usb_alloc_urb(0, mem_flags);
if (!io->urbs[i]) {
io->entries = i;
if (use_sg) {
io->urbs[0] = usb_alloc_urb(0, mem_flags);
if (!io->urbs[0]) {
io->entries = 0;
goto nomem;
}
io->urbs[i]->dev = NULL;
io->urbs[i]->pipe = pipe;
io->urbs[i]->interval = period;
io->urbs[i]->transfer_flags = urb_flags;
io->urbs[0]->dev = NULL;
io->urbs[0]->pipe = pipe;
io->urbs[0]->interval = period;
io->urbs[0]->transfer_flags = urb_flags;
io->urbs[i]->complete = sg_complete;
io->urbs[i]->context = io;
io->urbs[0]->complete = sg_complete;
io->urbs[0]->context = io;
/* A length of zero means transfer the whole sg list */
io->urbs[0]->transfer_buffer_length = length;
if (length == 0) {
for_each_sg(sg, sg, io->entries, i) {
io->urbs[0]->transfer_buffer_length +=
sg_dma_len(sg);
}
}
io->urbs[0]->sg = io;
io->urbs[0]->num_sgs = io->entries;
io->entries = 1;
} else {
for_each_sg(sg, sg, io->entries, i) {
unsigned len;
/*
* Some systems need to revert to PIO when DMA is temporarily
* unavailable. For their sakes, both transfer_buffer and
* transfer_dma are set when possible. However this can only
* work on systems without:
*
* - HIGHMEM, since DMA buffers located in high memory are
* not directly addressable by the CPU for PIO;
*
* - IOMMU, since dma_map_sg() is allowed to use an IOMMU to
* make virtually discontiguous buffers be "dma-contiguous"
* so that PIO and DMA need diferent numbers of URBs.
*
* So when HIGHMEM or IOMMU are in use, transfer_buffer is NULL
* to prevent stale pointers and to help spot bugs.
*/
if (dma) {
io->urbs[i]->transfer_dma = sg_dma_address(sg);
len = sg_dma_len(sg);
io->urbs[i] = usb_alloc_urb(0, mem_flags);
if (!io->urbs[i]) {
io->entries = i;
goto nomem;
}
io->urbs[i]->dev = NULL;
io->urbs[i]->pipe = pipe;
io->urbs[i]->interval = period;
io->urbs[i]->transfer_flags = urb_flags;
io->urbs[i]->complete = sg_complete;
io->urbs[i]->context = io;
/*
* Some systems need to revert to PIO when DMA is
* temporarily unavailable. For their sakes, both
* transfer_buffer and transfer_dma are set when
* possible. However this can only work on systems
* without:
*
* - HIGHMEM, since DMA buffers located in high memory
* are not directly addressable by the CPU for PIO;
*
* - IOMMU, since dma_map_sg() is allowed to use an
* IOMMU to make virtually discontiguous buffers be
* "dma-contiguous" so that PIO and DMA need diferent
* numbers of URBs.
*
* So when HIGHMEM or IOMMU are in use, transfer_buffer
* is NULL to prevent stale pointers and to help spot
* bugs.
*/
if (dma) {
io->urbs[i]->transfer_dma = sg_dma_address(sg);
len = sg_dma_len(sg);
#if defined(CONFIG_HIGHMEM) || defined(CONFIG_GART_IOMMU)
io->urbs[i]->transfer_buffer = NULL;
io->urbs[i]->transfer_buffer = NULL;
#else
io->urbs[i]->transfer_buffer = sg_virt(sg);
io->urbs[i]->transfer_buffer = sg_virt(sg);
#endif
} else {
/* hc may use _only_ transfer_buffer */
io->urbs[i]->transfer_buffer = sg_virt(sg);
len = sg->length;
}
} else {
/* hc may use _only_ transfer_buffer */
io->urbs[i]->transfer_buffer = sg_virt(sg);
len = sg->length;
}
if (length) {
len = min_t(unsigned, len, length);
length -= len;
if (length == 0)
io->entries = i + 1;
if (length) {
len = min_t(unsigned, len, length);
length -= len;
if (length == 0)
io->entries = i + 1;
}
io->urbs[i]->transfer_buffer_length = len;
}
io->urbs[i]->transfer_buffer_length = len;
io->urbs[--i]->transfer_flags &= ~URB_NO_INTERRUPT;
}
io->urbs[--i]->transfer_flags &= ~URB_NO_INTERRUPT;
/* transaction state */
io->count = io->entries;
@ -509,6 +553,10 @@ EXPORT_SYMBOL_GPL(usb_sg_init);
* could be transferred. That capability is less useful for low or full
* speed interrupt endpoints, which allow at most one packet per millisecond,
* of at most 8 or 64 bytes (respectively).
*
* It is not necessary to call this function to reserve bandwidth for devices
* under an xHCI host controller, as the bandwidth is reserved when the
* configuration or interface alt setting is selected.
*/
void usb_sg_wait(struct usb_sg_request *io)
{
@ -759,7 +807,7 @@ static int usb_string_sub(struct usb_device *dev, unsigned int langid,
}
/**
* usb_string - returns ISO 8859-1 version of a string descriptor
* usb_string - returns UTF-8 version of a string descriptor
* @dev: the device whose string descriptor is being retrieved
* @index: the number of the descriptor
* @buf: where to put the string
@ -767,17 +815,10 @@ static int usb_string_sub(struct usb_device *dev, unsigned int langid,
* Context: !in_interrupt ()
*
* This converts the UTF-16LE encoded strings returned by devices, from
* usb_get_string_descriptor(), to null-terminated ISO-8859-1 encoded ones
* that are more usable in most kernel contexts. Note that all characters
* in the chosen descriptor that can't be encoded using ISO-8859-1
* are converted to the question mark ("?") character, and this function
* usb_get_string_descriptor(), to null-terminated UTF-8 encoded ones
* that are more usable in most kernel contexts. Note that this function
* chooses strings in the first language supported by the device.
*
* The ASCII (or, redundantly, "US-ASCII") character set is the seven-bit
* subset of ISO 8859-1. ISO-8859-1 is the eight-bit subset of Unicode,
* and is appropriate for use many uses of English and several other
* Western European languages. (But it doesn't include the "Euro" symbol.)
*
* This call is synchronous, and may not be used in an interrupt context.
*
* Returns length of the string (>= 0) or usb_control_msg status (< 0).
@ -786,7 +827,6 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size)
{
unsigned char *tbuf;
int err;
unsigned int u, idx;
if (dev->state == USB_STATE_SUSPENDED)
return -EHOSTUNREACH;
@ -821,16 +861,9 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size)
goto errout;
size--; /* leave room for trailing NULL char in output buffer */
for (idx = 0, u = 2; u < err; u += 2) {
if (idx >= size)
break;
if (tbuf[u+1]) /* high byte */
buf[idx++] = '?'; /* non ISO-8859-1 character */
else
buf[idx++] = tbuf[u];
}
buf[idx] = 0;
err = idx;
err = utf16s_to_utf8s((wchar_t *) &tbuf[2], (err - 2) / 2,
UTF16_LITTLE_ENDIAN, buf, size);
buf[err] = 0;
if (tbuf[1] != USB_DT_STRING)
dev_dbg(&dev->dev,
@ -843,6 +876,9 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size)
}
EXPORT_SYMBOL_GPL(usb_string);
/* one UTF-8-encoded 16-bit character has at most three bytes */
#define MAX_USB_STRING_SIZE (127 * 3 + 1)
/**
* usb_cache_string - read a string descriptor and cache it for later use
* @udev: the device whose string descriptor is being read
@ -860,9 +896,9 @@ char *usb_cache_string(struct usb_device *udev, int index)
if (index <= 0)
return NULL;
buf = kmalloc(256, GFP_KERNEL);
buf = kmalloc(MAX_USB_STRING_SIZE, GFP_KERNEL);
if (buf) {
len = usb_string(udev, index, buf, 256);
len = usb_string(udev, index, buf, MAX_USB_STRING_SIZE);
if (len > 0) {
smallbuf = kmalloc(++len, GFP_KERNEL);
if (!smallbuf)
@ -1664,6 +1700,21 @@ free_interfaces:
if (ret)
goto free_interfaces;
/* Make sure we have bandwidth (and available HCD resources) for this
* configuration. Remove endpoints from the schedule if we're dropping
* this configuration to set configuration 0. After this point, the
* host controller will not allow submissions to dropped endpoints. If
* this call fails, the device state is unchanged.
*/
if (cp)
ret = usb_hcd_check_bandwidth(dev, cp, NULL);
else
ret = usb_hcd_check_bandwidth(dev, NULL, NULL);
if (ret < 0) {
usb_autosuspend_device(dev);
goto free_interfaces;
}
/* if it's already configured, clear out old state first.
* getting rid of old interfaces means unbinding their drivers.
*/
@ -1686,6 +1737,7 @@ free_interfaces:
dev->actconfig = cp;
if (!cp) {
usb_set_device_state(dev, USB_STATE_ADDRESS);
usb_hcd_check_bandwidth(dev, NULL, NULL);
usb_autosuspend_device(dev);
goto free_interfaces;
}

View File

@ -552,8 +552,8 @@ static struct attribute *dev_string_attrs[] = {
static mode_t dev_string_attrs_are_visible(struct kobject *kobj,
struct attribute *a, int n)
{
struct usb_device *udev = to_usb_device(
container_of(kobj, struct device, kobj));
struct device *dev = container_of(kobj, struct device, kobj);
struct usb_device *udev = to_usb_device(dev);
if (a == &dev_attr_manufacturer.attr) {
if (udev->manufacturer == NULL)
@ -585,8 +585,8 @@ static ssize_t
read_descriptors(struct kobject *kobj, struct bin_attribute *attr,
char *buf, loff_t off, size_t count)
{
struct usb_device *udev = to_usb_device(
container_of(kobj, struct device, kobj));
struct device *dev = container_of(kobj, struct device, kobj);
struct usb_device *udev = to_usb_device(dev);
size_t nleft = count;
size_t srclen, n;
int cfgno;
@ -786,8 +786,8 @@ static struct attribute *intf_assoc_attrs[] = {
static mode_t intf_assoc_attrs_are_visible(struct kobject *kobj,
struct attribute *a, int n)
{
struct usb_interface *intf = to_usb_interface(
container_of(kobj, struct device, kobj));
struct device *dev = container_of(kobj, struct device, kobj);
struct usb_interface *intf = to_usb_interface(dev);
if (intf->intf_assoc == NULL)
return 0;

View File

@ -241,6 +241,12 @@ EXPORT_SYMBOL_GPL(usb_unanchor_urb);
* If the USB subsystem can't allocate sufficient bandwidth to perform
* the periodic request, submitting such a periodic request should fail.
*
* For devices under xHCI, the bandwidth is reserved at configuration time, or
* when the alt setting is selected. If there is not enough bus bandwidth, the
* configuration/alt setting request will fail. Therefore, submissions to
* periodic endpoints on devices under xHCI should never fail due to bandwidth
* constraints.
*
* Device drivers must explicitly request that repetition, by ensuring that
* some URB is always on the endpoint's queue (except possibly for short
* periods during completion callacks). When there is no longer an urb
@ -351,6 +357,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
if (xfertype == USB_ENDPOINT_XFER_ISOC) {
int n, len;
/* FIXME SuperSpeed isoc endpoints have up to 16 bursts */
/* "high bandwidth" mode, 1-3 packets/uframe? */
if (dev->speed == USB_SPEED_HIGH) {
int mult = 1 + ((max >> 11) & 0x03);
@ -426,6 +433,11 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
return -EINVAL;
/* too big? */
switch (dev->speed) {
case USB_SPEED_SUPER: /* units are 125us */
/* Handle up to 2^(16-1) microframes */
if (urb->interval > (1 << 15))
return -EINVAL;
max = 1 << 15;
case USB_SPEED_HIGH: /* units are microframes */
/* NOTE usb handles 2^15 */
if (urb->interval > (1024 * 8))

View File

@ -34,6 +34,7 @@
#include <linux/usb.h>
#include <linux/mutex.h>
#include <linux/workqueue.h>
#include <linux/debugfs.h>
#include <asm/io.h>
#include <linux/scatterlist.h>
@ -139,8 +140,7 @@ static int __find_interface(struct device *dev, void *data)
struct find_interface_arg *arg = data;
struct usb_interface *intf;
/* can't look at usb devices, only interfaces */
if (is_usb_device(dev))
if (!is_usb_interface(dev))
return 0;
intf = to_usb_interface(dev);
@ -184,11 +184,16 @@ EXPORT_SYMBOL_GPL(usb_find_interface);
static void usb_release_dev(struct device *dev)
{
struct usb_device *udev;
struct usb_hcd *hcd;
udev = to_usb_device(dev);
hcd = bus_to_hcd(udev->bus);
usb_destroy_configuration(udev);
usb_put_hcd(bus_to_hcd(udev->bus));
/* Root hubs aren't real devices, so don't free HCD resources */
if (hcd->driver->free_dev && udev->parent)
hcd->driver->free_dev(hcd, udev);
usb_put_hcd(hcd);
kfree(udev->product);
kfree(udev->manufacturer);
kfree(udev->serial);
@ -359,6 +364,13 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent,
kfree(dev);
return NULL;
}
/* Root hubs aren't true devices, so don't allocate HCD resources */
if (usb_hcd->driver->alloc_dev && parent &&
!usb_hcd->driver->alloc_dev(usb_hcd, dev)) {
usb_put_hcd(bus_to_hcd(bus));
kfree(dev);
return NULL;
}
device_initialize(&dev->dev);
dev->dev.bus = &usb_bus_type;
@ -386,18 +398,24 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent,
*/
if (unlikely(!parent)) {
dev->devpath[0] = '0';
dev->route = 0;
dev->dev.parent = bus->controller;
dev_set_name(&dev->dev, "usb%d", bus->busnum);
root_hub = 1;
} else {
/* match any labeling on the hubs; it's one-based */
if (parent->devpath[0] == '0')
if (parent->devpath[0] == '0') {
snprintf(dev->devpath, sizeof dev->devpath,
"%d", port1);
else
/* Root ports are not counted in route string */
dev->route = 0;
} else {
snprintf(dev->devpath, sizeof dev->devpath,
"%s.%d", parent->devpath, port1);
dev->route = parent->route +
(port1 << ((parent->level - 1)*4));
}
dev->dev.parent = &parent->dev;
dev_set_name(&dev->dev, "%d-%s", bus->busnum, dev->devpath);
@ -810,12 +828,12 @@ void usb_buffer_dmasync(struct urb *urb)
return;
if (controller->dma_mask) {
dma_sync_single(controller,
dma_sync_single_for_cpu(controller,
urb->transfer_dma, urb->transfer_buffer_length,
usb_pipein(urb->pipe)
? DMA_FROM_DEVICE : DMA_TO_DEVICE);
if (usb_pipecontrol(urb->pipe))
dma_sync_single(controller,
dma_sync_single_for_cpu(controller,
urb->setup_dma,
sizeof(struct usb_ctrlrequest),
DMA_TO_DEVICE);
@ -933,8 +951,8 @@ void usb_buffer_dmasync_sg(const struct usb_device *dev, int is_in,
|| !controller->dma_mask)
return;
dma_sync_sg(controller, sg, n_hw_ents,
is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
dma_sync_sg_for_cpu(controller, sg, n_hw_ents,
is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
}
EXPORT_SYMBOL_GPL(usb_buffer_dmasync_sg);
#endif
@ -1012,6 +1030,35 @@ static struct notifier_block usb_bus_nb = {
.notifier_call = usb_bus_notify,
};
struct dentry *usb_debug_root;
EXPORT_SYMBOL_GPL(usb_debug_root);
struct dentry *usb_debug_devices;
static int usb_debugfs_init(void)
{
usb_debug_root = debugfs_create_dir("usb", NULL);
if (!usb_debug_root)
return -ENOENT;
usb_debug_devices = debugfs_create_file("devices", 0444,
usb_debug_root, NULL,
&usbfs_devices_fops);
if (!usb_debug_devices) {
debugfs_remove(usb_debug_root);
usb_debug_root = NULL;
return -ENOENT;
}
return 0;
}
static void usb_debugfs_cleanup(void)
{
debugfs_remove(usb_debug_devices);
debugfs_remove(usb_debug_root);
}
/*
* Init
*/
@ -1023,6 +1070,10 @@ static int __init usb_init(void)
return 0;
}
retval = usb_debugfs_init();
if (retval)
goto out;
retval = ksuspend_usb_init();
if (retval)
goto out;
@ -1032,9 +1083,6 @@ static int __init usb_init(void)
retval = bus_register_notifier(&usb_bus_type, &usb_bus_nb);
if (retval)
goto bus_notifier_failed;
retval = usb_host_init();
if (retval)
goto host_init_failed;
retval = usb_major_init();
if (retval)
goto major_init_failed;
@ -1064,8 +1112,6 @@ usb_devio_init_failed:
driver_register_failed:
usb_major_cleanup();
major_init_failed:
usb_host_cleanup();
host_init_failed:
bus_unregister_notifier(&usb_bus_type, &usb_bus_nb);
bus_notifier_failed:
bus_unregister(&usb_bus_type);
@ -1090,10 +1136,10 @@ static void __exit usb_exit(void)
usb_deregister(&usbfs_driver);
usb_devio_cleanup();
usb_hub_cleanup();
usb_host_cleanup();
bus_unregister_notifier(&usb_bus_type, &usb_bus_nb);
bus_unregister(&usb_bus_type);
ksuspend_usb_cleanup();
usb_debugfs_cleanup();
}
subsys_initcall(usb_init);

View File

@ -41,8 +41,6 @@ extern int usb_hub_init(void);
extern void usb_hub_cleanup(void);
extern int usb_major_init(void);
extern void usb_major_cleanup(void);
extern int usb_host_init(void);
extern void usb_host_cleanup(void);
#ifdef CONFIG_PM
@ -106,6 +104,7 @@ extern struct workqueue_struct *ksuspend_usb_wq;
extern struct bus_type usb_bus_type;
extern struct device_type usb_device_type;
extern struct device_type usb_if_device_type;
extern struct device_type usb_ep_device_type;
extern struct usb_device_driver usb_generic_driver;
static inline int is_usb_device(const struct device *dev)
@ -113,6 +112,16 @@ static inline int is_usb_device(const struct device *dev)
return dev->type == &usb_device_type;
}
static inline int is_usb_interface(const struct device *dev)
{
return dev->type == &usb_if_device_type;
}
static inline int is_usb_endpoint(const struct device *dev)
{
return dev->type == &usb_ep_device_type;
}
/* Do the same for device drivers and interface drivers. */
static inline int is_usb_device_driver(struct device_driver *drv)

View File

@ -156,7 +156,7 @@ config USB_ATMEL_USBA
config USB_GADGET_FSL_USB2
boolean "Freescale Highspeed USB DR Peripheral Controller"
depends on FSL_SOC
depends on FSL_SOC || ARCH_MXC
select USB_GADGET_DUALSPEED
help
Some of Freescale PowerPC processors have a High Speed
@ -253,7 +253,7 @@ config USB_PXA25X_SMALL
config USB_GADGET_PXA27X
boolean "PXA 27x"
depends on ARCH_PXA && PXA27x
depends on ARCH_PXA && (PXA27x || PXA3xx)
select USB_OTG_UTILS
help
Intel's PXA 27x series XScale ARM v5TE processors include
@ -272,6 +272,20 @@ config USB_PXA27X
default USB_GADGET
select USB_GADGET_SELECTED
config USB_GADGET_S3C_HSOTG
boolean "S3C HS/OtG USB Device controller"
depends on S3C_DEV_USB_HSOTG
select USB_GADGET_S3C_HSOTG_PIO
help
The Samsung S3C64XX USB2.0 high-speed gadget controller
integrated into the S3C64XX series SoC.
config USB_S3C_HSOTG
tristate
depends on USB_GADGET_S3C_HSOTG
default USB_GADGET
select USB_GADGET_SELECTED
config USB_GADGET_S3C2410
boolean "S3C2410 USB Device Controller"
depends on ARCH_S3C2410
@ -460,6 +474,27 @@ config USB_GOKU
default USB_GADGET
select USB_GADGET_SELECTED
config USB_GADGET_LANGWELL
boolean "Intel Langwell USB Device Controller"
depends on PCI
select USB_GADGET_DUALSPEED
help
Intel Langwell USB Device Controller is a High-Speed USB
On-The-Go device controller.
The number of programmable endpoints is different through
controller revision.
Say "y" to link the driver statically, or "m" to build a
dynamically linked module called "langwell_udc" and force all
gadget drivers to also be dynamically linked.
config USB_LANGWELL
tristate
depends on USB_GADGET_LANGWELL
default USB_GADGET
select USB_GADGET_SELECTED
#
# LAST -- dummy/emulated controller
@ -566,6 +601,20 @@ config USB_ZERO_HNPTEST
the "B-Peripheral" role, that device will use HNP to let this
one serve as the USB host instead (in the "B-Host" role).
config USB_AUDIO
tristate "Audio Gadget (EXPERIMENTAL)"
depends on SND
help
Gadget Audio is compatible with USB Audio Class specification 1.0.
It will include at least one AudioControl interface, zero or more
AudioStream interface and zero or more MIDIStream interface.
Gadget Audio will use on-board ALSA (CONFIG_SND) audio card to
playback or capture audio stream.
Say "y" to link the driver statically, or "m" to build a
dynamically linked module called "g_audio".
config USB_ETH
tristate "Ethernet Gadget (with CDC Ethernet support)"
depends on NET

View File

@ -18,14 +18,21 @@ obj-$(CONFIG_USB_S3C2410) += s3c2410_udc.o
obj-$(CONFIG_USB_AT91) += at91_udc.o
obj-$(CONFIG_USB_ATMEL_USBA) += atmel_usba_udc.o
obj-$(CONFIG_USB_FSL_USB2) += fsl_usb2_udc.o
fsl_usb2_udc-objs := fsl_udc_core.o
ifeq ($(CONFIG_ARCH_MXC),y)
fsl_usb2_udc-objs += fsl_mx3_udc.o
endif
obj-$(CONFIG_USB_M66592) += m66592-udc.o
obj-$(CONFIG_USB_FSL_QE) += fsl_qe_udc.o
obj-$(CONFIG_USB_CI13XXX) += ci13xxx_udc.o
obj-$(CONFIG_USB_S3C_HSOTG) += s3c-hsotg.o
obj-$(CONFIG_USB_LANGWELL) += langwell_udc.o
#
# USB gadget drivers
#
g_zero-objs := zero.o
g_audio-objs := audio.o
g_ether-objs := ether.o
g_serial-objs := serial.o
g_midi-objs := gmidi.o
@ -35,6 +42,7 @@ g_printer-objs := printer.o
g_cdc-objs := cdc2.o
obj-$(CONFIG_USB_ZERO) += g_zero.o
obj-$(CONFIG_USB_AUDIO) += g_audio.o
obj-$(CONFIG_USB_ETH) += g_ether.o
obj-$(CONFIG_USB_GADGETFS) += gadgetfs.o
obj-$(CONFIG_USB_FILE_STORAGE) += g_file_storage.o

View File

@ -485,7 +485,7 @@ static int at91_ep_enable(struct usb_ep *_ep,
return -ESHUTDOWN;
}
tmp = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
tmp = usb_endpoint_type(desc);
switch (tmp) {
case USB_ENDPOINT_XFER_CONTROL:
DBG("only one control endpoint\n");
@ -517,7 +517,7 @@ ok:
local_irq_save(flags);
/* initialize endpoint to match this descriptor */
ep->is_in = (desc->bEndpointAddress & USB_DIR_IN) != 0;
ep->is_in = usb_endpoint_dir_in(desc);
ep->is_iso = (tmp == USB_ENDPOINT_XFER_ISOC);
ep->stopped = 0;
if (ep->is_in)

View File

@ -326,13 +326,7 @@ static int vbus_is_present(struct usba_udc *udc)
return 1;
}
#if defined(CONFIG_AVR32)
static void toggle_bias(int is_on)
{
}
#elif defined(CONFIG_ARCH_AT91)
#if defined(CONFIG_ARCH_AT91SAM9RL)
#include <mach/at91_pmc.h>
@ -346,7 +340,13 @@ static void toggle_bias(int is_on)
at91_sys_write(AT91_CKGR_UCKR, uckr & ~(AT91_PMC_BIASEN));
}
#endif /* CONFIG_ARCH_AT91 */
#else
static void toggle_bias(int is_on)
{
}
#endif /* CONFIG_ARCH_AT91SAM9RL */
static void next_fifo_transaction(struct usba_ep *ep, struct usba_request *req)
{
@ -550,12 +550,12 @@ usba_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
DBG(DBG_HW, "%s: EPT_SIZE = %lu (maxpacket = %lu)\n",
ep->ep.name, ept_cfg, maxpacket);
if ((desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) {
if (usb_endpoint_dir_in(desc)) {
ep->is_in = 1;
ept_cfg |= USBA_EPT_DIR_IN;
}
switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
switch (usb_endpoint_type(desc)) {
case USB_ENDPOINT_XFER_CONTROL:
ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_CONTROL);
ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_ONE);

View File

@ -0,0 +1,302 @@
/*
* audio.c -- Audio gadget driver
*
* Copyright (C) 2008 Bryan Wu <cooloney@kernel.org>
* Copyright (C) 2008 Analog Devices, Inc
*
* Enter bugs at http://blackfin.uclinux.org/
*
* Licensed under the GPL-2 or later.
*/
/* #define VERBOSE_DEBUG */
#include <linux/kernel.h>
#include <linux/utsname.h>
#include "u_audio.h"
#define DRIVER_DESC "Linux USB Audio Gadget"
#define DRIVER_VERSION "Dec 18, 2008"
/*-------------------------------------------------------------------------*/
/*
* Kbuild is not very cooperative with respect to linking separately
* compiled library objects into one module. So for now we won't use
* separate compilation ... ensuring init/exit sections work to shrink
* the runtime footprint, and giving us at least some parts of what
* a "gcc --combine ... part1.c part2.c part3.c ... " build would.
*/
#include "composite.c"
#include "usbstring.c"
#include "config.c"
#include "epautoconf.c"
#include "u_audio.c"
#include "f_audio.c"
/*-------------------------------------------------------------------------*/
/* DO NOT REUSE THESE IDs with a protocol-incompatible driver!! Ever!!
* Instead: allocate your own, using normal USB-IF procedures.
*/
/* Thanks to NetChip Technologies for donating this product ID. */
#define AUDIO_VENDOR_NUM 0x0525 /* NetChip */
#define AUDIO_PRODUCT_NUM 0xa4a1 /* Linux-USB Audio Gadget */
/*-------------------------------------------------------------------------*/
static struct usb_device_descriptor device_desc = {
.bLength = sizeof device_desc,
.bDescriptorType = USB_DT_DEVICE,
.bcdUSB = __constant_cpu_to_le16(0x200),
.bDeviceClass = USB_CLASS_PER_INTERFACE,
.bDeviceSubClass = 0,
.bDeviceProtocol = 0,
/* .bMaxPacketSize0 = f(hardware) */
/* Vendor and product id defaults change according to what configs
* we support. (As does bNumConfigurations.) These values can
* also be overridden by module parameters.
*/
.idVendor = __constant_cpu_to_le16(AUDIO_VENDOR_NUM),
.idProduct = __constant_cpu_to_le16(AUDIO_PRODUCT_NUM),
/* .bcdDevice = f(hardware) */
/* .iManufacturer = DYNAMIC */
/* .iProduct = DYNAMIC */
/* NO SERIAL NUMBER */
.bNumConfigurations = 1,
};
static struct usb_otg_descriptor otg_descriptor = {
.bLength = sizeof otg_descriptor,
.bDescriptorType = USB_DT_OTG,
/* REVISIT SRP-only hardware is possible, although
* it would not be called "OTG" ...
*/
.bmAttributes = USB_OTG_SRP | USB_OTG_HNP,
};
static const struct usb_descriptor_header *otg_desc[] = {
(struct usb_descriptor_header *) &otg_descriptor,
NULL,
};
/*-------------------------------------------------------------------------*/
/**
* Handle USB audio endpoint set/get command in setup class request
*/
static int audio_set_endpoint_req(struct usb_configuration *c,
const struct usb_ctrlrequest *ctrl)
{
struct usb_composite_dev *cdev = c->cdev;
int value = -EOPNOTSUPP;
u16 ep = le16_to_cpu(ctrl->wIndex);
u16 len = le16_to_cpu(ctrl->wLength);
u16 w_value = le16_to_cpu(ctrl->wValue);
DBG(cdev, "bRequest 0x%x, w_value 0x%04x, len %d, endpoint %d\n",
ctrl->bRequest, w_value, len, ep);
switch (ctrl->bRequest) {
case SET_CUR:
value = 0;
break;
case SET_MIN:
break;
case SET_MAX:
break;
case SET_RES:
break;
case SET_MEM:
break;
default:
break;
}
return value;
}
static int audio_get_endpoint_req(struct usb_configuration *c,
const struct usb_ctrlrequest *ctrl)
{
struct usb_composite_dev *cdev = c->cdev;
int value = -EOPNOTSUPP;
u8 ep = ((le16_to_cpu(ctrl->wIndex) >> 8) & 0xFF);
u16 len = le16_to_cpu(ctrl->wLength);
u16 w_value = le16_to_cpu(ctrl->wValue);
DBG(cdev, "bRequest 0x%x, w_value 0x%04x, len %d, endpoint %d\n",
ctrl->bRequest, w_value, len, ep);
switch (ctrl->bRequest) {
case GET_CUR:
case GET_MIN:
case GET_MAX:
case GET_RES:
value = 3;
break;
case GET_MEM:
break;
default:
break;
}
return value;
}
static int
audio_setup(struct usb_configuration *c, const struct usb_ctrlrequest *ctrl)
{
struct usb_composite_dev *cdev = c->cdev;
struct usb_request *req = cdev->req;
int value = -EOPNOTSUPP;
u16 w_index = le16_to_cpu(ctrl->wIndex);
u16 w_value = le16_to_cpu(ctrl->wValue);
u16 w_length = le16_to_cpu(ctrl->wLength);
/* composite driver infrastructure handles everything except
* Audio class messages; interface activation uses set_alt().
*/
switch (ctrl->bRequestType) {
case USB_AUDIO_SET_ENDPOINT:
value = audio_set_endpoint_req(c, ctrl);
break;
case USB_AUDIO_GET_ENDPOINT:
value = audio_get_endpoint_req(c, ctrl);
break;
default:
ERROR(cdev, "Invalid control req%02x.%02x v%04x i%04x l%d\n",
ctrl->bRequestType, ctrl->bRequest,
w_value, w_index, w_length);
}
/* respond with data transfer or status phase? */
if (value >= 0) {
DBG(cdev, "Audio req%02x.%02x v%04x i%04x l%d\n",
ctrl->bRequestType, ctrl->bRequest,
w_value, w_index, w_length);
req->zero = 0;
req->length = value;
value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
if (value < 0)
ERROR(cdev, "Audio response on err %d\n", value);
}
/* device either stalls (value < 0) or reports success */
return value;
}
/*-------------------------------------------------------------------------*/
static int __init audio_do_config(struct usb_configuration *c)
{
/* FIXME alloc iConfiguration string, set it in c->strings */
if (gadget_is_otg(c->cdev->gadget)) {
c->descriptors = otg_desc;
c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
}
audio_bind_config(c);
return 0;
}
static struct usb_configuration audio_config_driver = {
.label = DRIVER_DESC,
.bind = audio_do_config,
.setup = audio_setup,
.bConfigurationValue = 1,
/* .iConfiguration = DYNAMIC */
.bmAttributes = USB_CONFIG_ATT_SELFPOWER,
};
/*-------------------------------------------------------------------------*/
static int __init audio_bind(struct usb_composite_dev *cdev)
{
int gcnum;
int status;
gcnum = usb_gadget_controller_number(cdev->gadget);
if (gcnum >= 0)
device_desc.bcdDevice = cpu_to_le16(0x0300 | gcnum);
else {
ERROR(cdev, "controller '%s' not recognized; trying %s\n",
cdev->gadget->name,
audio_config_driver.label);
device_desc.bcdDevice =
__constant_cpu_to_le16(0x0300 | 0x0099);
}
/* device descriptor strings: manufacturer, product */
snprintf(manufacturer, sizeof manufacturer, "%s %s with %s",
init_utsname()->sysname, init_utsname()->release,
cdev->gadget->name);
status = usb_string_id(cdev);
if (status < 0)
goto fail;
strings_dev[STRING_MANUFACTURER_IDX].id = status;
device_desc.iManufacturer = status;
status = usb_string_id(cdev);
if (status < 0)
goto fail;
strings_dev[STRING_PRODUCT_IDX].id = status;
device_desc.iProduct = status;
status = usb_add_config(cdev, &audio_config_driver);
if (status < 0)
goto fail;
INFO(cdev, "%s, version: %s\n", DRIVER_DESC, DRIVER_VERSION);
return 0;
fail:
return status;
}
static int __exit audio_unbind(struct usb_composite_dev *cdev)
{
return 0;
}
static struct usb_composite_driver audio_driver = {
.name = "g_audio",
.dev = &device_desc,
.strings = audio_strings,
.bind = audio_bind,
.unbind = __exit_p(audio_unbind),
};
static int __init init(void)
{
return usb_composite_register(&audio_driver);
}
module_init(init);
static void __exit cleanup(void)
{
usb_composite_unregister(&audio_driver);
}
module_exit(cleanup);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_AUTHOR("Bryan Wu <cooloney@kernel.org>");
MODULE_LICENSE("GPL");

View File

@ -1977,9 +1977,9 @@ static int ep_enable(struct usb_ep *ep,
if (!list_empty(&mEp->qh[mEp->dir].queue))
warn("enabling a non-empty endpoint!");
mEp->dir = (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ? TX : RX;
mEp->num = desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
mEp->type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
mEp->dir = usb_endpoint_dir_in(desc) ? TX : RX;
mEp->num = usb_endpoint_num(desc);
mEp->type = usb_endpoint_type(desc);
mEp->ep.maxpacket = __constant_le16_to_cpu(desc->wMaxPacketSize);

View File

@ -0,0 +1,707 @@
/*
* f_audio.c -- USB Audio class function driver
*
* Copyright (C) 2008 Bryan Wu <cooloney@kernel.org>
* Copyright (C) 2008 Analog Devices, Inc
*
* Enter bugs at http://blackfin.uclinux.org/
*
* Licensed under the GPL-2 or later.
*/
#include <linux/kernel.h>
#include <linux/device.h>
#include <asm/atomic.h>
#include "u_audio.h"
#define OUT_EP_MAX_PACKET_SIZE 200
static int req_buf_size = OUT_EP_MAX_PACKET_SIZE;
module_param(req_buf_size, int, S_IRUGO);
MODULE_PARM_DESC(req_buf_size, "ISO OUT endpoint request buffer size");
static int req_count = 256;
module_param(req_count, int, S_IRUGO);
MODULE_PARM_DESC(req_count, "ISO OUT endpoint request count");
static int audio_buf_size = 48000;
module_param(audio_buf_size, int, S_IRUGO);
MODULE_PARM_DESC(audio_buf_size, "Audio buffer size");
/*
* DESCRIPTORS ... most are static, but strings and full
* configuration descriptors are built on demand.
*/
/*
* We have two interfaces- AudioControl and AudioStreaming
* TODO: only supcard playback currently
*/
#define F_AUDIO_AC_INTERFACE 0
#define F_AUDIO_AS_INTERFACE 1
#define F_AUDIO_NUM_INTERFACES 2
/* B.3.1 Standard AC Interface Descriptor */
static struct usb_interface_descriptor ac_interface_desc __initdata = {
.bLength = USB_DT_INTERFACE_SIZE,
.bDescriptorType = USB_DT_INTERFACE,
.bNumEndpoints = 0,
.bInterfaceClass = USB_CLASS_AUDIO,
.bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL,
};
DECLARE_USB_AC_HEADER_DESCRIPTOR(2);
#define USB_DT_AC_HEADER_LENGH USB_DT_AC_HEADER_SIZE(F_AUDIO_NUM_INTERFACES)
/* B.3.2 Class-Specific AC Interface Descriptor */
static struct usb_ac_header_descriptor_2 ac_header_desc = {
.bLength = USB_DT_AC_HEADER_LENGH,
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubtype = HEADER,
.bcdADC = __constant_cpu_to_le16(0x0100),
.wTotalLength = __constant_cpu_to_le16(USB_DT_AC_HEADER_LENGH),
.bInCollection = F_AUDIO_NUM_INTERFACES,
.baInterfaceNr = {
[0] = F_AUDIO_AC_INTERFACE,
[1] = F_AUDIO_AS_INTERFACE,
}
};
#define INPUT_TERMINAL_ID 1
static struct usb_input_terminal_descriptor input_terminal_desc = {
.bLength = USB_DT_AC_INPUT_TERMINAL_SIZE,
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubtype = INPUT_TERMINAL,
.bTerminalID = INPUT_TERMINAL_ID,
.wTerminalType = USB_AC_TERMINAL_STREAMING,
.bAssocTerminal = 0,
.wChannelConfig = 0x3,
};
DECLARE_USB_AC_FEATURE_UNIT_DESCRIPTOR(0);
#define FEATURE_UNIT_ID 2
static struct usb_ac_feature_unit_descriptor_0 feature_unit_desc = {
.bLength = USB_DT_AC_FEATURE_UNIT_SIZE(0),
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubtype = FEATURE_UNIT,
.bUnitID = FEATURE_UNIT_ID,
.bSourceID = INPUT_TERMINAL_ID,
.bControlSize = 2,
.bmaControls[0] = (FU_MUTE | FU_VOLUME),
};
static struct usb_audio_control mute_control = {
.list = LIST_HEAD_INIT(mute_control.list),
.name = "Mute Control",
.type = MUTE_CONTROL,
/* Todo: add real Mute control code */
.set = generic_set_cmd,
.get = generic_get_cmd,
};
static struct usb_audio_control volume_control = {
.list = LIST_HEAD_INIT(volume_control.list),
.name = "Volume Control",
.type = VOLUME_CONTROL,
/* Todo: add real Volume control code */
.set = generic_set_cmd,
.get = generic_get_cmd,
};
static struct usb_audio_control_selector feature_unit = {
.list = LIST_HEAD_INIT(feature_unit.list),
.id = FEATURE_UNIT_ID,
.name = "Mute & Volume Control",
.type = FEATURE_UNIT,
.desc = (struct usb_descriptor_header *)&feature_unit_desc,
};
#define OUTPUT_TERMINAL_ID 3
static struct usb_output_terminal_descriptor output_terminal_desc = {
.bLength = USB_DT_AC_OUTPUT_TERMINAL_SIZE,
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubtype = OUTPUT_TERMINAL,
.bTerminalID = OUTPUT_TERMINAL_ID,
.wTerminalType = USB_AC_OUTPUT_TERMINAL_SPEAKER,
.bAssocTerminal = FEATURE_UNIT_ID,
.bSourceID = FEATURE_UNIT_ID,
};
/* B.4.1 Standard AS Interface Descriptor */
static struct usb_interface_descriptor as_interface_alt_0_desc = {
.bLength = USB_DT_INTERFACE_SIZE,
.bDescriptorType = USB_DT_INTERFACE,
.bAlternateSetting = 0,
.bNumEndpoints = 0,
.bInterfaceClass = USB_CLASS_AUDIO,
.bInterfaceSubClass = USB_SUBCLASS_AUDIOSTREAMING,
};
static struct usb_interface_descriptor as_interface_alt_1_desc = {
.bLength = USB_DT_INTERFACE_SIZE,
.bDescriptorType = USB_DT_INTERFACE,
.bAlternateSetting = 1,
.bNumEndpoints = 1,
.bInterfaceClass = USB_CLASS_AUDIO,
.bInterfaceSubClass = USB_SUBCLASS_AUDIOSTREAMING,
};
/* B.4.2 Class-Specific AS Interface Descriptor */
static struct usb_as_header_descriptor as_header_desc = {
.bLength = USB_DT_AS_HEADER_SIZE,
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubtype = AS_GENERAL,
.bTerminalLink = INPUT_TERMINAL_ID,
.bDelay = 1,
.wFormatTag = USB_AS_AUDIO_FORMAT_TYPE_I_PCM,
};
DECLARE_USB_AS_FORMAT_TYPE_I_DISCRETE_DESC(1);
static struct usb_as_formate_type_i_discrete_descriptor_1 as_type_i_desc = {
.bLength = USB_AS_FORMAT_TYPE_I_DISCRETE_DESC_SIZE(1),
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubtype = FORMAT_TYPE,
.bFormatType = USB_AS_FORMAT_TYPE_I,
.bSubframeSize = 2,
.bBitResolution = 16,
.bSamFreqType = 1,
};
/* Standard ISO OUT Endpoint Descriptor */
static struct usb_endpoint_descriptor as_out_ep_desc __initdata = {
.bLength = USB_DT_ENDPOINT_AUDIO_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
.bEndpointAddress = USB_DIR_OUT,
.bmAttributes = USB_AS_ENDPOINT_ADAPTIVE
| USB_ENDPOINT_XFER_ISOC,
.wMaxPacketSize = __constant_cpu_to_le16(OUT_EP_MAX_PACKET_SIZE),
.bInterval = 4,
};
/* Class-specific AS ISO OUT Endpoint Descriptor */
static struct usb_as_iso_endpoint_descriptor as_iso_out_desc __initdata = {
.bLength = USB_AS_ISO_ENDPOINT_DESC_SIZE,
.bDescriptorType = USB_DT_CS_ENDPOINT,
.bDescriptorSubtype = EP_GENERAL,
.bmAttributes = 1,
.bLockDelayUnits = 1,
.wLockDelay = __constant_cpu_to_le16(1),
};
static struct usb_descriptor_header *f_audio_desc[] __initdata = {
(struct usb_descriptor_header *)&ac_interface_desc,
(struct usb_descriptor_header *)&ac_header_desc,
(struct usb_descriptor_header *)&input_terminal_desc,
(struct usb_descriptor_header *)&output_terminal_desc,
(struct usb_descriptor_header *)&feature_unit_desc,
(struct usb_descriptor_header *)&as_interface_alt_0_desc,
(struct usb_descriptor_header *)&as_interface_alt_1_desc,
(struct usb_descriptor_header *)&as_header_desc,
(struct usb_descriptor_header *)&as_type_i_desc,
(struct usb_descriptor_header *)&as_out_ep_desc,
(struct usb_descriptor_header *)&as_iso_out_desc,
NULL,
};
/* string IDs are assigned dynamically */
#define STRING_MANUFACTURER_IDX 0
#define STRING_PRODUCT_IDX 1
static char manufacturer[50];
static struct usb_string strings_dev[] = {
[STRING_MANUFACTURER_IDX].s = manufacturer,
[STRING_PRODUCT_IDX].s = DRIVER_DESC,
{ } /* end of list */
};
static struct usb_gadget_strings stringtab_dev = {
.language = 0x0409, /* en-us */
.strings = strings_dev,
};
static struct usb_gadget_strings *audio_strings[] = {
&stringtab_dev,
NULL,
};
/*
* This function is an ALSA sound card following USB Audio Class Spec 1.0.
*/
/*-------------------------------------------------------------------------*/
struct f_audio_buf {
u8 *buf;
int actual;
struct list_head list;
};
static struct f_audio_buf *f_audio_buffer_alloc(int buf_size)
{
struct f_audio_buf *copy_buf;
copy_buf = kzalloc(sizeof *copy_buf, GFP_ATOMIC);
if (!copy_buf)
return (struct f_audio_buf *)-ENOMEM;
copy_buf->buf = kzalloc(buf_size, GFP_ATOMIC);
if (!copy_buf->buf) {
kfree(copy_buf);
return (struct f_audio_buf *)-ENOMEM;
}
return copy_buf;
}
static void f_audio_buffer_free(struct f_audio_buf *audio_buf)
{
kfree(audio_buf->buf);
kfree(audio_buf);
}
/*-------------------------------------------------------------------------*/
struct f_audio {
struct gaudio card;
/* endpoints handle full and/or high speeds */
struct usb_ep *out_ep;
struct usb_endpoint_descriptor *out_desc;
spinlock_t lock;
struct f_audio_buf *copy_buf;
struct work_struct playback_work;
struct list_head play_queue;
/* Control Set command */
struct list_head cs;
u8 set_cmd;
struct usb_audio_control *set_con;
};
static inline struct f_audio *func_to_audio(struct usb_function *f)
{
return container_of(f, struct f_audio, card.func);
}
/*-------------------------------------------------------------------------*/
static void f_audio_playback_work(struct work_struct *data)
{
struct f_audio *audio = container_of(data, struct f_audio,
playback_work);
struct f_audio_buf *play_buf;
spin_lock_irq(&audio->lock);
if (list_empty(&audio->play_queue)) {
spin_unlock_irq(&audio->lock);
return;
}
play_buf = list_first_entry(&audio->play_queue,
struct f_audio_buf, list);
list_del(&play_buf->list);
spin_unlock_irq(&audio->lock);
u_audio_playback(&audio->card, play_buf->buf, play_buf->actual);
f_audio_buffer_free(play_buf);
return;
}
static int f_audio_out_ep_complete(struct usb_ep *ep, struct usb_request *req)
{
struct f_audio *audio = req->context;
struct usb_composite_dev *cdev = audio->card.func.config->cdev;
struct f_audio_buf *copy_buf = audio->copy_buf;
int err;
if (!copy_buf)
return -EINVAL;
/* Copy buffer is full, add it to the play_queue */
if (audio_buf_size - copy_buf->actual < req->actual) {
list_add_tail(&copy_buf->list, &audio->play_queue);
schedule_work(&audio->playback_work);
copy_buf = f_audio_buffer_alloc(audio_buf_size);
if (copy_buf < 0)
return -ENOMEM;
}
memcpy(copy_buf->buf + copy_buf->actual, req->buf, req->actual);
copy_buf->actual += req->actual;
audio->copy_buf = copy_buf;
err = usb_ep_queue(ep, req, GFP_ATOMIC);
if (err)
ERROR(cdev, "%s queue req: %d\n", ep->name, err);
return 0;
}
static void f_audio_complete(struct usb_ep *ep, struct usb_request *req)
{
struct f_audio *audio = req->context;
int status = req->status;
u32 data = 0;
struct usb_ep *out_ep = audio->out_ep;
switch (status) {
case 0: /* normal completion? */
if (ep == out_ep)
f_audio_out_ep_complete(ep, req);
else if (audio->set_con) {
memcpy(&data, req->buf, req->length);
audio->set_con->set(audio->set_con, audio->set_cmd,
le16_to_cpu(data));
audio->set_con = NULL;
}
break;
default:
break;
}
}
static int audio_set_intf_req(struct usb_function *f,
const struct usb_ctrlrequest *ctrl)
{
struct f_audio *audio = func_to_audio(f);
struct usb_composite_dev *cdev = f->config->cdev;
struct usb_request *req = cdev->req;
u8 id = ((le16_to_cpu(ctrl->wIndex) >> 8) & 0xFF);
u16 len = le16_to_cpu(ctrl->wLength);
u16 w_value = le16_to_cpu(ctrl->wValue);
u8 con_sel = (w_value >> 8) & 0xFF;
u8 cmd = (ctrl->bRequest & 0x0F);
struct usb_audio_control_selector *cs;
struct usb_audio_control *con;
DBG(cdev, "bRequest 0x%x, w_value 0x%04x, len %d, entity %d\n",
ctrl->bRequest, w_value, len, id);
list_for_each_entry(cs, &audio->cs, list) {
if (cs->id == id) {
list_for_each_entry(con, &cs->control, list) {
if (con->type == con_sel) {
audio->set_con = con;
break;
}
}
break;
}
}
audio->set_cmd = cmd;
req->context = audio;
req->complete = f_audio_complete;
return len;
}
static int audio_get_intf_req(struct usb_function *f,
const struct usb_ctrlrequest *ctrl)
{
struct f_audio *audio = func_to_audio(f);
struct usb_composite_dev *cdev = f->config->cdev;
struct usb_request *req = cdev->req;
int value = -EOPNOTSUPP;
u8 id = ((le16_to_cpu(ctrl->wIndex) >> 8) & 0xFF);
u16 len = le16_to_cpu(ctrl->wLength);
u16 w_value = le16_to_cpu(ctrl->wValue);
u8 con_sel = (w_value >> 8) & 0xFF;
u8 cmd = (ctrl->bRequest & 0x0F);
struct usb_audio_control_selector *cs;
struct usb_audio_control *con;
DBG(cdev, "bRequest 0x%x, w_value 0x%04x, len %d, entity %d\n",
ctrl->bRequest, w_value, len, id);
list_for_each_entry(cs, &audio->cs, list) {
if (cs->id == id) {
list_for_each_entry(con, &cs->control, list) {
if (con->type == con_sel && con->get) {
value = con->get(con, cmd);
break;
}
}
break;
}
}
req->context = audio;
req->complete = f_audio_complete;
memcpy(req->buf, &value, len);
return len;
}
static int
f_audio_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
{
struct usb_composite_dev *cdev = f->config->cdev;
struct usb_request *req = cdev->req;
int value = -EOPNOTSUPP;
u16 w_index = le16_to_cpu(ctrl->wIndex);
u16 w_value = le16_to_cpu(ctrl->wValue);
u16 w_length = le16_to_cpu(ctrl->wLength);
/* composite driver infrastructure handles everything except
* Audio class messages; interface activation uses set_alt().
*/
switch (ctrl->bRequestType) {
case USB_AUDIO_SET_INTF:
value = audio_set_intf_req(f, ctrl);
break;
case USB_AUDIO_GET_INTF:
value = audio_get_intf_req(f, ctrl);
break;
default:
ERROR(cdev, "invalid control req%02x.%02x v%04x i%04x l%d\n",
ctrl->bRequestType, ctrl->bRequest,
w_value, w_index, w_length);
}
/* respond with data transfer or status phase? */
if (value >= 0) {
DBG(cdev, "audio req%02x.%02x v%04x i%04x l%d\n",
ctrl->bRequestType, ctrl->bRequest,
w_value, w_index, w_length);
req->zero = 0;
req->length = value;
value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
if (value < 0)
ERROR(cdev, "audio response on err %d\n", value);
}
/* device either stalls (value < 0) or reports success */
return value;
}
static int f_audio_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
{
struct f_audio *audio = func_to_audio(f);
struct usb_composite_dev *cdev = f->config->cdev;
struct usb_ep *out_ep = audio->out_ep;
struct usb_request *req;
int i = 0, err = 0;
DBG(cdev, "intf %d, alt %d\n", intf, alt);
if (intf == 1) {
if (alt == 1) {
usb_ep_enable(out_ep, audio->out_desc);
out_ep->driver_data = audio;
audio->copy_buf = f_audio_buffer_alloc(audio_buf_size);
/*
* allocate a bunch of read buffers
* and queue them all at once.
*/
for (i = 0; i < req_count && err == 0; i++) {
req = usb_ep_alloc_request(out_ep, GFP_ATOMIC);
if (req) {
req->buf = kzalloc(req_buf_size,
GFP_ATOMIC);
if (req->buf) {
req->length = req_buf_size;
req->context = audio;
req->complete =
f_audio_complete;
err = usb_ep_queue(out_ep,
req, GFP_ATOMIC);
if (err)
ERROR(cdev,
"%s queue req: %d\n",
out_ep->name, err);
} else
err = -ENOMEM;
} else
err = -ENOMEM;
}
} else {
struct f_audio_buf *copy_buf = audio->copy_buf;
if (copy_buf) {
list_add_tail(&copy_buf->list,
&audio->play_queue);
schedule_work(&audio->playback_work);
}
}
}
return err;
}
static void f_audio_disable(struct usb_function *f)
{
return;
}
/*-------------------------------------------------------------------------*/
static void f_audio_build_desc(struct f_audio *audio)
{
struct gaudio *card = &audio->card;
u8 *sam_freq;
int rate;
/* Set channel numbers */
input_terminal_desc.bNrChannels = u_audio_get_playback_channels(card);
as_type_i_desc.bNrChannels = u_audio_get_playback_channels(card);
/* Set sample rates */
rate = u_audio_get_playback_rate(card);
sam_freq = as_type_i_desc.tSamFreq[0];
memcpy(sam_freq, &rate, 3);
/* Todo: Set Sample bits and other parameters */
return;
}
/* audio function driver setup/binding */
static int __init
f_audio_bind(struct usb_configuration *c, struct usb_function *f)
{
struct usb_composite_dev *cdev = c->cdev;
struct f_audio *audio = func_to_audio(f);
int status;
struct usb_ep *ep;
f_audio_build_desc(audio);
/* allocate instance-specific interface IDs, and patch descriptors */
status = usb_interface_id(c, f);
if (status < 0)
goto fail;
ac_interface_desc.bInterfaceNumber = status;
status = usb_interface_id(c, f);
if (status < 0)
goto fail;
as_interface_alt_0_desc.bInterfaceNumber = status;
as_interface_alt_1_desc.bInterfaceNumber = status;
status = -ENODEV;
/* allocate instance-specific endpoints */
ep = usb_ep_autoconfig(cdev->gadget, &as_out_ep_desc);
if (!ep)
goto fail;
audio->out_ep = ep;
ep->driver_data = cdev; /* claim */
status = -ENOMEM;
/* supcard all relevant hardware speeds... we expect that when
* hardware is dual speed, all bulk-capable endpoints work at
* both speeds
*/
/* copy descriptors, and track endpoint copies */
if (gadget_is_dualspeed(c->cdev->gadget)) {
c->highspeed = true;
f->hs_descriptors = usb_copy_descriptors(f_audio_desc);
} else
f->descriptors = usb_copy_descriptors(f_audio_desc);
return 0;
fail:
return status;
}
static void
f_audio_unbind(struct usb_configuration *c, struct usb_function *f)
{
struct f_audio *audio = func_to_audio(f);
usb_free_descriptors(f->descriptors);
kfree(audio);
}
/*-------------------------------------------------------------------------*/
/* Todo: add more control selecotor dynamically */
int __init control_selector_init(struct f_audio *audio)
{
INIT_LIST_HEAD(&audio->cs);
list_add(&feature_unit.list, &audio->cs);
INIT_LIST_HEAD(&feature_unit.control);
list_add(&mute_control.list, &feature_unit.control);
list_add(&volume_control.list, &feature_unit.control);
volume_control.data[_CUR] = 0xffc0;
volume_control.data[_MIN] = 0xe3a0;
volume_control.data[_MAX] = 0xfff0;
volume_control.data[_RES] = 0x0030;
return 0;
}
/**
* audio_bind_config - add USB audio fucntion to a configuration
* @c: the configuration to supcard the USB audio function
* Context: single threaded during gadget setup
*
* Returns zero on success, else negative errno.
*/
int __init audio_bind_config(struct usb_configuration *c)
{
struct f_audio *audio;
int status;
/* allocate and initialize one new instance */
audio = kzalloc(sizeof *audio, GFP_KERNEL);
if (!audio)
return -ENOMEM;
audio->card.func.name = "g_audio";
audio->card.gadget = c->cdev->gadget;
INIT_LIST_HEAD(&audio->play_queue);
spin_lock_init(&audio->lock);
/* set up ASLA audio devices */
status = gaudio_setup(&audio->card);
if (status < 0)
goto setup_fail;
audio->card.func.strings = audio_strings;
audio->card.func.bind = f_audio_bind;
audio->card.func.unbind = f_audio_unbind;
audio->card.func.set_alt = f_audio_set_alt;
audio->card.func.setup = f_audio_setup;
audio->card.func.disable = f_audio_disable;
audio->out_desc = &as_out_ep_desc;
control_selector_init(audio);
INIT_WORK(&audio->playback_work, f_audio_playback_work);
status = usb_add_function(c, &audio->card.func);
if (status)
goto add_fail;
INFO(c->cdev, "audio_buf_size %d, req_buf_size %d, req_count %d\n",
audio_buf_size, req_buf_size, req_count);
return status;
add_fail:
gaudio_cleanup(&audio->card);
setup_fail:
kfree(audio);
return status;
}

View File

@ -475,7 +475,9 @@ static int rndis_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
if (rndis->port.in_ep->driver_data) {
DBG(cdev, "reset rndis\n");
gether_disconnect(&rndis->port);
} else {
}
if (!rndis->port.in) {
DBG(cdev, "init rndis\n");
rndis->port.in = ep_choose(cdev->gadget,
rndis->hs.in, rndis->fs.in);

View File

@ -248,6 +248,8 @@
#include <linux/freezer.h>
#include <linux/utsname.h>
#include <asm/unaligned.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
@ -799,29 +801,9 @@ static int fsg_set_halt(struct fsg_dev *fsg, struct usb_ep *ep)
/* Routines for unaligned data access */
static u16 get_be16(u8 *buf)
static u32 get_unaligned_be24(u8 *buf)
{
return ((u16) buf[0] << 8) | ((u16) buf[1]);
}
static u32 get_be32(u8 *buf)
{
return ((u32) buf[0] << 24) | ((u32) buf[1] << 16) |
((u32) buf[2] << 8) | ((u32) buf[3]);
}
static void put_be16(u8 *buf, u16 val)
{
buf[0] = val >> 8;
buf[1] = val;
}
static void put_be32(u8 *buf, u32 val)
{
buf[0] = val >> 24;
buf[1] = val >> 16;
buf[2] = val >> 8;
buf[3] = val & 0xff;
return 0xffffff & (u32) get_unaligned_be32(buf - 1);
}
@ -1582,9 +1564,9 @@ static int do_read(struct fsg_dev *fsg)
/* Get the starting Logical Block Address and check that it's
* not too big */
if (fsg->cmnd[0] == SC_READ_6)
lba = (fsg->cmnd[1] << 16) | get_be16(&fsg->cmnd[2]);
lba = get_unaligned_be24(&fsg->cmnd[1]);
else {
lba = get_be32(&fsg->cmnd[2]);
lba = get_unaligned_be32(&fsg->cmnd[2]);
/* We allow DPO (Disable Page Out = don't save data in the
* cache) and FUA (Force Unit Access = don't read from the
@ -1717,9 +1699,9 @@ static int do_write(struct fsg_dev *fsg)
/* Get the starting Logical Block Address and check that it's
* not too big */
if (fsg->cmnd[0] == SC_WRITE_6)
lba = (fsg->cmnd[1] << 16) | get_be16(&fsg->cmnd[2]);
lba = get_unaligned_be24(&fsg->cmnd[1]);
else {
lba = get_be32(&fsg->cmnd[2]);
lba = get_unaligned_be32(&fsg->cmnd[2]);
/* We allow DPO (Disable Page Out = don't save data in the
* cache) and FUA (Force Unit Access = write directly to the
@ -1940,7 +1922,7 @@ static int do_verify(struct fsg_dev *fsg)
/* Get the starting Logical Block Address and check that it's
* not too big */
lba = get_be32(&fsg->cmnd[2]);
lba = get_unaligned_be32(&fsg->cmnd[2]);
if (lba >= curlun->num_sectors) {
curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
return -EINVAL;
@ -1953,7 +1935,7 @@ static int do_verify(struct fsg_dev *fsg)
return -EINVAL;
}
verification_length = get_be16(&fsg->cmnd[7]);
verification_length = get_unaligned_be16(&fsg->cmnd[7]);
if (unlikely(verification_length == 0))
return -EIO; // No default reply
@ -2103,7 +2085,7 @@ static int do_request_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh)
memset(buf, 0, 18);
buf[0] = valid | 0x70; // Valid, current error
buf[2] = SK(sd);
put_be32(&buf[3], sdinfo); // Sense information
put_unaligned_be32(sdinfo, &buf[3]); /* Sense information */
buf[7] = 18 - 8; // Additional sense length
buf[12] = ASC(sd);
buf[13] = ASCQ(sd);
@ -2114,7 +2096,7 @@ static int do_request_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh)
static int do_read_capacity(struct fsg_dev *fsg, struct fsg_buffhd *bh)
{
struct lun *curlun = fsg->curlun;
u32 lba = get_be32(&fsg->cmnd[2]);
u32 lba = get_unaligned_be32(&fsg->cmnd[2]);
int pmi = fsg->cmnd[8];
u8 *buf = (u8 *) bh->buf;
@ -2124,8 +2106,9 @@ static int do_read_capacity(struct fsg_dev *fsg, struct fsg_buffhd *bh)
return -EINVAL;
}
put_be32(&buf[0], curlun->num_sectors - 1); // Max logical block
put_be32(&buf[4], 512); // Block length
put_unaligned_be32(curlun->num_sectors - 1, &buf[0]);
/* Max logical block */
put_unaligned_be32(512, &buf[4]); /* Block length */
return 8;
}
@ -2144,7 +2127,7 @@ static void store_cdrom_address(u8 *dest, int msf, u32 addr)
dest[0] = 0; /* Reserved */
} else {
/* Absolute sector */
put_be32(dest, addr);
put_unaligned_be32(addr, dest);
}
}
@ -2152,7 +2135,7 @@ static int do_read_header(struct fsg_dev *fsg, struct fsg_buffhd *bh)
{
struct lun *curlun = fsg->curlun;
int msf = fsg->cmnd[1] & 0x02;
u32 lba = get_be32(&fsg->cmnd[2]);
u32 lba = get_unaligned_be32(&fsg->cmnd[2]);
u8 *buf = (u8 *) bh->buf;
if ((fsg->cmnd[1] & ~0x02) != 0) { /* Mask away MSF */
@ -2252,10 +2235,13 @@ static int do_mode_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh)
buf[2] = 0x04; // Write cache enable,
// Read cache not disabled
// No cache retention priorities
put_be16(&buf[4], 0xffff); // Don't disable prefetch
// Minimum prefetch = 0
put_be16(&buf[8], 0xffff); // Maximum prefetch
put_be16(&buf[10], 0xffff); // Maximum prefetch ceiling
put_unaligned_be16(0xffff, &buf[4]);
/* Don't disable prefetch */
/* Minimum prefetch = 0 */
put_unaligned_be16(0xffff, &buf[8]);
/* Maximum prefetch */
put_unaligned_be16(0xffff, &buf[10]);
/* Maximum prefetch ceiling */
}
buf += 12;
}
@ -2272,7 +2258,7 @@ static int do_mode_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh)
if (mscmnd == SC_MODE_SENSE_6)
buf0[0] = len - 1;
else
put_be16(buf0, len - 2);
put_unaligned_be16(len - 2, buf0);
return len;
}
@ -2360,9 +2346,10 @@ static int do_read_format_capacities(struct fsg_dev *fsg,
buf[3] = 8; // Only the Current/Maximum Capacity Descriptor
buf += 4;
put_be32(&buf[0], curlun->num_sectors); // Number of blocks
put_be32(&buf[4], 512); // Block length
buf[4] = 0x02; // Current capacity
put_unaligned_be32(curlun->num_sectors, &buf[0]);
/* Number of blocks */
put_unaligned_be32(512, &buf[4]); /* Block length */
buf[4] = 0x02; /* Current capacity */
return 12;
}
@ -2882,7 +2869,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
break;
case SC_MODE_SELECT_10:
fsg->data_size_from_cmnd = get_be16(&fsg->cmnd[7]);
fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
if ((reply = check_command(fsg, 10, DATA_DIR_FROM_HOST,
(1<<1) | (3<<7), 0,
"MODE SELECT(10)")) == 0)
@ -2898,7 +2885,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
break;
case SC_MODE_SENSE_10:
fsg->data_size_from_cmnd = get_be16(&fsg->cmnd[7]);
fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
(1<<1) | (1<<2) | (3<<7), 0,
"MODE SENSE(10)")) == 0)
@ -2923,7 +2910,8 @@ static int do_scsi_command(struct fsg_dev *fsg)
break;
case SC_READ_10:
fsg->data_size_from_cmnd = get_be16(&fsg->cmnd[7]) << 9;
fsg->data_size_from_cmnd =
get_unaligned_be16(&fsg->cmnd[7]) << 9;
if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
(1<<1) | (0xf<<2) | (3<<7), 1,
"READ(10)")) == 0)
@ -2931,7 +2919,8 @@ static int do_scsi_command(struct fsg_dev *fsg)
break;
case SC_READ_12:
fsg->data_size_from_cmnd = get_be32(&fsg->cmnd[6]) << 9;
fsg->data_size_from_cmnd =
get_unaligned_be32(&fsg->cmnd[6]) << 9;
if ((reply = check_command(fsg, 12, DATA_DIR_TO_HOST,
(1<<1) | (0xf<<2) | (0xf<<6), 1,
"READ(12)")) == 0)
@ -2949,7 +2938,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
case SC_READ_HEADER:
if (!mod_data.cdrom)
goto unknown_cmnd;
fsg->data_size_from_cmnd = get_be16(&fsg->cmnd[7]);
fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
(3<<7) | (0x1f<<1), 1,
"READ HEADER")) == 0)
@ -2959,7 +2948,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
case SC_READ_TOC:
if (!mod_data.cdrom)
goto unknown_cmnd;
fsg->data_size_from_cmnd = get_be16(&fsg->cmnd[7]);
fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
(7<<6) | (1<<1), 1,
"READ TOC")) == 0)
@ -2967,7 +2956,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
break;
case SC_READ_FORMAT_CAPACITIES:
fsg->data_size_from_cmnd = get_be16(&fsg->cmnd[7]);
fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
(3<<7), 1,
"READ FORMAT CAPACITIES")) == 0)
@ -3025,7 +3014,8 @@ static int do_scsi_command(struct fsg_dev *fsg)
break;
case SC_WRITE_10:
fsg->data_size_from_cmnd = get_be16(&fsg->cmnd[7]) << 9;
fsg->data_size_from_cmnd =
get_unaligned_be16(&fsg->cmnd[7]) << 9;
if ((reply = check_command(fsg, 10, DATA_DIR_FROM_HOST,
(1<<1) | (0xf<<2) | (3<<7), 1,
"WRITE(10)")) == 0)
@ -3033,7 +3023,8 @@ static int do_scsi_command(struct fsg_dev *fsg)
break;
case SC_WRITE_12:
fsg->data_size_from_cmnd = get_be32(&fsg->cmnd[6]) << 9;
fsg->data_size_from_cmnd =
get_unaligned_be32(&fsg->cmnd[6]) << 9;
if ((reply = check_command(fsg, 12, DATA_DIR_FROM_HOST,
(1<<1) | (0xf<<2) | (0xf<<6), 1,
"WRITE(12)")) == 0)

View File

@ -0,0 +1,95 @@
/*
* Copyright (C) 2009
* Guennadi Liakhovetski, DENX Software Engineering, <lg@denx.de>
*
* Description:
* Helper routines for i.MX3x SoCs from Freescale, needed by the fsl_usb2_udc.c
* driver to function correctly on these systems.
*
* 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.
*/
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/err.h>
#include <linux/fsl_devices.h>
#include <linux/platform_device.h>
static struct clk *mxc_ahb_clk;
static struct clk *mxc_usb_clk;
int fsl_udc_clk_init(struct platform_device *pdev)
{
struct fsl_usb2_platform_data *pdata;
unsigned long freq;
int ret;
pdata = pdev->dev.platform_data;
mxc_ahb_clk = clk_get(&pdev->dev, "usb_ahb");
if (IS_ERR(mxc_ahb_clk))
return PTR_ERR(mxc_ahb_clk);
ret = clk_enable(mxc_ahb_clk);
if (ret < 0) {
dev_err(&pdev->dev, "clk_enable(\"usb_ahb\") failed\n");
goto eenahb;
}
/* make sure USB_CLK is running at 60 MHz +/- 1000 Hz */
mxc_usb_clk = clk_get(&pdev->dev, "usb");
if (IS_ERR(mxc_usb_clk)) {
dev_err(&pdev->dev, "clk_get(\"usb\") failed\n");
ret = PTR_ERR(mxc_usb_clk);
goto egusb;
}
freq = clk_get_rate(mxc_usb_clk);
if (pdata->phy_mode != FSL_USB2_PHY_ULPI &&
(freq < 59999000 || freq > 60001000)) {
dev_err(&pdev->dev, "USB_CLK=%lu, should be 60MHz\n", freq);
goto eclkrate;
}
ret = clk_enable(mxc_usb_clk);
if (ret < 0) {
dev_err(&pdev->dev, "clk_enable(\"usb_clk\") failed\n");
goto eenusb;
}
return 0;
eenusb:
eclkrate:
clk_put(mxc_usb_clk);
mxc_usb_clk = NULL;
egusb:
clk_disable(mxc_ahb_clk);
eenahb:
clk_put(mxc_ahb_clk);
return ret;
}
void fsl_udc_clk_finalize(struct platform_device *pdev)
{
struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
/* ULPI transceivers don't need usbpll */
if (pdata->phy_mode == FSL_USB2_PHY_ULPI) {
clk_disable(mxc_usb_clk);
clk_put(mxc_usb_clk);
mxc_usb_clk = NULL;
}
}
void fsl_udc_clk_release(void)
{
if (mxc_usb_clk) {
clk_disable(mxc_usb_clk);
clk_put(mxc_usb_clk);
}
clk_disable(mxc_ahb_clk);
clk_put(mxc_ahb_clk);
}

View File

@ -38,6 +38,7 @@
#include <linux/platform_device.h>
#include <linux/fsl_devices.h>
#include <linux/dmapool.h>
#include <linux/delay.h>
#include <asm/byteorder.h>
#include <asm/io.h>
@ -57,7 +58,9 @@ static const char driver_name[] = "fsl-usb2-udc";
static const char driver_desc[] = DRIVER_DESC;
static struct usb_dr_device *dr_regs;
#ifndef CONFIG_ARCH_MXC
static struct usb_sys_interface *usb_sys_regs;
#endif
/* it is initialized in probe() */
static struct fsl_udc *udc_controller = NULL;
@ -174,10 +177,34 @@ static void nuke(struct fsl_ep *ep, int status)
static int dr_controller_setup(struct fsl_udc *udc)
{
unsigned int tmp = 0, portctrl = 0, ctrl = 0;
unsigned int tmp, portctrl;
#ifndef CONFIG_ARCH_MXC
unsigned int ctrl;
#endif
unsigned long timeout;
#define FSL_UDC_RESET_TIMEOUT 1000
/* Config PHY interface */
portctrl = fsl_readl(&dr_regs->portsc1);
portctrl &= ~(PORTSCX_PHY_TYPE_SEL | PORTSCX_PORT_WIDTH);
switch (udc->phy_mode) {
case FSL_USB2_PHY_ULPI:
portctrl |= PORTSCX_PTS_ULPI;
break;
case FSL_USB2_PHY_UTMI_WIDE:
portctrl |= PORTSCX_PTW_16BIT;
/* fall through */
case FSL_USB2_PHY_UTMI:
portctrl |= PORTSCX_PTS_UTMI;
break;
case FSL_USB2_PHY_SERIAL:
portctrl |= PORTSCX_PTS_FSLS;
break;
default:
return -EINVAL;
}
fsl_writel(portctrl, &dr_regs->portsc1);
/* Stop and reset the usb controller */
tmp = fsl_readl(&dr_regs->usbcmd);
tmp &= ~USB_CMD_RUN_STOP;
@ -215,31 +242,12 @@ static int dr_controller_setup(struct fsl_udc *udc)
udc->ep_qh, (int)tmp,
fsl_readl(&dr_regs->endpointlistaddr));
/* Config PHY interface */
portctrl = fsl_readl(&dr_regs->portsc1);
portctrl &= ~(PORTSCX_PHY_TYPE_SEL | PORTSCX_PORT_WIDTH);
switch (udc->phy_mode) {
case FSL_USB2_PHY_ULPI:
portctrl |= PORTSCX_PTS_ULPI;
break;
case FSL_USB2_PHY_UTMI_WIDE:
portctrl |= PORTSCX_PTW_16BIT;
/* fall through */
case FSL_USB2_PHY_UTMI:
portctrl |= PORTSCX_PTS_UTMI;
break;
case FSL_USB2_PHY_SERIAL:
portctrl |= PORTSCX_PTS_FSLS;
break;
default:
return -EINVAL;
}
fsl_writel(portctrl, &dr_regs->portsc1);
/* Config control enable i/o output, cpu endian register */
#ifndef CONFIG_ARCH_MXC
ctrl = __raw_readl(&usb_sys_regs->control);
ctrl |= USB_CTRL_IOENB;
__raw_writel(ctrl, &usb_sys_regs->control);
#endif
#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
/* Turn on cache snooping hardware, since some PowerPC platforms
@ -2043,6 +2051,7 @@ static int fsl_proc_read(char *page, char **start, off_t off, int count,
size -= t;
next += t;
#ifndef CONFIG_ARCH_MXC
tmp_reg = usb_sys_regs->snoop1;
t = scnprintf(next, size, "Snoop1 Reg : = [0x%x]\n\n", tmp_reg);
size -= t;
@ -2053,6 +2062,7 @@ static int fsl_proc_read(char *page, char **start, off_t off, int count,
tmp_reg);
size -= t;
next += t;
#endif
/* ------fsl_udc, fsl_ep, fsl_request structure information ----- */
ep = &udc->eps[0];
@ -2263,14 +2273,21 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
goto err_kfree;
}
dr_regs = ioremap(res->start, res->end - res->start + 1);
dr_regs = ioremap(res->start, resource_size(res));
if (!dr_regs) {
ret = -ENOMEM;
goto err_release_mem_region;
}
#ifndef CONFIG_ARCH_MXC
usb_sys_regs = (struct usb_sys_interface *)
((u32)dr_regs + USB_DR_SYS_OFFSET);
#endif
/* Initialize USB clocks */
ret = fsl_udc_clk_init(pdev);
if (ret < 0)
goto err_iounmap_noclk;
/* Read Device Controller Capability Parameters register */
dccparams = fsl_readl(&dr_regs->dccparams);
@ -2308,6 +2325,8 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
* leave usbintr reg untouched */
dr_controller_setup(udc_controller);
fsl_udc_clk_finalize(pdev);
/* Setup gadget structure */
udc_controller->gadget.ops = &fsl_gadget_ops;
udc_controller->gadget.is_dualspeed = 1;
@ -2362,6 +2381,8 @@ err_unregister:
err_free_irq:
free_irq(udc_controller->irq, udc_controller);
err_iounmap:
fsl_udc_clk_release();
err_iounmap_noclk:
iounmap(dr_regs);
err_release_mem_region:
release_mem_region(res->start, res->end - res->start + 1);
@ -2384,6 +2405,8 @@ static int __exit fsl_udc_remove(struct platform_device *pdev)
return -ENODEV;
udc_controller->done = &done;
fsl_udc_clk_release();
/* DR has been stopped in usb_gadget_unregister_driver() */
remove_proc_file();

View File

@ -563,4 +563,22 @@ static void dump_msg(const char *label, const u8 * buf, unsigned int length)
* 2 + ((windex & USB_DIR_IN) ? 1 : 0))
#define get_pipe_by_ep(EP) (ep_index(EP) * 2 + ep_is_in(EP))
struct platform_device;
#ifdef CONFIG_ARCH_MXC
int fsl_udc_clk_init(struct platform_device *pdev);
void fsl_udc_clk_finalize(struct platform_device *pdev);
void fsl_udc_clk_release(void);
#else
static inline int fsl_udc_clk_init(struct platform_device *pdev)
{
return 0;
}
static inline void fsl_udc_clk_finalize(struct platform_device *pdev)
{
}
static inline void fsl_udc_clk_release(void)
{
}
#endif
#endif

View File

@ -137,6 +137,12 @@
#define gadget_is_musbhdrc(g) 0
#endif
#ifdef CONFIG_USB_GADGET_LANGWELL
#define gadget_is_langwell(g) (!strcmp("langwell_udc", (g)->name))
#else
#define gadget_is_langwell(g) 0
#endif
/* from Montavista kernel (?) */
#ifdef CONFIG_USB_GADGET_MPC8272
#define gadget_is_mpc8272(g) !strcmp("mpc8272_udc", (g)->name)
@ -231,6 +237,8 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
return 0x22;
else if (gadget_is_ci13xxx(gadget))
return 0x23;
else if (gadget_is_langwell(gadget))
return 0x24;
return -ENOENT;
}

View File

@ -110,10 +110,10 @@ goku_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
return -EINVAL;
if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)
return -ESHUTDOWN;
if (ep->num != (desc->bEndpointAddress & 0x0f))
if (ep->num != usb_endpoint_num(desc))
return -EINVAL;
switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
switch (usb_endpoint_type(desc)) {
case USB_ENDPOINT_XFER_BULK:
case USB_ENDPOINT_XFER_INT:
break;
@ -142,7 +142,7 @@ goku_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
/* ep1/ep2 dma direction is chosen early; it works in the other
* direction, with pio. be cautious with out-dma.
*/
ep->is_in = (USB_DIR_IN & desc->bEndpointAddress) != 0;
ep->is_in = usb_endpoint_dir_in(desc);
if (ep->is_in) {
mode |= 1;
ep->dma = (use_dma != 0) && (ep->num == UDC_MSTRD_ENDPOINT);

View File

@ -415,6 +415,13 @@ static int write_packet(struct imx_ep_struct *imx_ep, struct imx_request *req)
u8 *buf;
int length, count, temp;
if (unlikely(__raw_readl(imx_ep->imx_usb->base +
USB_EP_STAT(EP_NO(imx_ep))) & EPSTAT_ZLPS)) {
D_TRX(imx_ep->imx_usb->dev, "<%s> zlp still queued in EP %s\n",
__func__, imx_ep->ep.name);
return -1;
}
buf = req->req.buf + req->req.actual;
prefetch(buf);
@ -734,9 +741,12 @@ static struct usb_request *imx_ep_alloc_request
{
struct imx_request *req;
if (!usb_ep)
return NULL;
req = kzalloc(sizeof *req, gfp_flags);
if (!req || !usb_ep)
return 0;
if (!req)
return NULL;
INIT_LIST_HEAD(&req->queue);
req->in_use = 0;

View File

@ -384,9 +384,8 @@ ep_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
return value;
/* halt any endpoint by doing a "wrong direction" i/o call */
if (data->desc.bEndpointAddress & USB_DIR_IN) {
if ((data->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
== USB_ENDPOINT_XFER_ISOC)
if (usb_endpoint_dir_in(&data->desc)) {
if (usb_endpoint_xfer_isoc(&data->desc))
return -EINVAL;
DBG (data->dev, "%s halt\n", data->name);
spin_lock_irq (&data->dev->lock);
@ -428,9 +427,8 @@ ep_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
return value;
/* halt any endpoint by doing a "wrong direction" i/o call */
if (!(data->desc.bEndpointAddress & USB_DIR_IN)) {
if ((data->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
== USB_ENDPOINT_XFER_ISOC)
if (!usb_endpoint_dir_in(&data->desc)) {
if (usb_endpoint_xfer_isoc(&data->desc))
return -EINVAL;
DBG (data->dev, "%s halt\n", data->name);
spin_lock_irq (&data->dev->lock);
@ -691,7 +689,7 @@ ep_aio_read(struct kiocb *iocb, const struct iovec *iov,
struct ep_data *epdata = iocb->ki_filp->private_data;
char *buf;
if (unlikely(epdata->desc.bEndpointAddress & USB_DIR_IN))
if (unlikely(usb_endpoint_dir_in(&epdata->desc)))
return -EINVAL;
buf = kmalloc(iocb->ki_left, GFP_KERNEL);
@ -711,7 +709,7 @@ ep_aio_write(struct kiocb *iocb, const struct iovec *iov,
size_t len = 0;
int i = 0;
if (unlikely(!(epdata->desc.bEndpointAddress & USB_DIR_IN)))
if (unlikely(!usb_endpoint_dir_in(&epdata->desc)))
return -EINVAL;
buf = kmalloc(iocb->ki_left, GFP_KERNEL);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,228 @@
/*
* Intel Langwell USB Device Controller driver
* Copyright (C) 2008-2009, Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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.,
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include <linux/usb/langwell_udc.h>
#if defined(CONFIG_USB_LANGWELL_OTG)
#include <linux/usb/langwell_otg.h>
#endif
/*-------------------------------------------------------------------------*/
/* driver data structures and utilities */
/*
* dTD: Device Endpoint Transfer Descriptor
* describe to the device controller the location and quantity of
* data to be send/received for given transfer
*/
struct langwell_dtd {
u32 dtd_next;
/* bits 31:5, next transfer element pointer */
#define DTD_NEXT(d) (((d)>>5)&0x7ffffff)
#define DTD_NEXT_MASK (0x7ffffff << 5)
/* terminate */
#define DTD_TERM BIT(0)
/* bits 7:0, execution back states */
u32 dtd_status:8;
#define DTD_STATUS(d) (((d)>>0)&0xff)
#define DTD_STS_ACTIVE BIT(7) /* active */
#define DTD_STS_HALTED BIT(6) /* halted */
#define DTD_STS_DBE BIT(5) /* data buffer error */
#define DTD_STS_TRE BIT(3) /* transaction error */
/* bits 9:8 */
u32 dtd_res0:2;
/* bits 11:10, multipier override */
u32 dtd_multo:2;
#define DTD_MULTO (BIT(11) | BIT(10))
/* bits 14:12 */
u32 dtd_res1:3;
/* bit 15, interrupt on complete */
u32 dtd_ioc:1;
#define DTD_IOC BIT(15)
/* bits 30:16, total bytes */
u32 dtd_total:15;
#define DTD_TOTAL(d) (((d)>>16)&0x7fff)
#define DTD_MAX_TRANSFER_LENGTH 0x4000
/* bit 31 */
u32 dtd_res2:1;
/* dTD buffer pointer page 0 to 4 */
u32 dtd_buf[5];
#define DTD_OFFSET_MASK 0xfff
/* bits 31:12, buffer pointer */
#define DTD_BUFFER(d) (((d)>>12)&0x3ff)
/* bits 11:0, current offset */
#define DTD_C_OFFSET(d) (((d)>>0)&0xfff)
/* bits 10:0, frame number */
#define DTD_FRAME(d) (((d)>>0)&0x7ff)
/* driver-private parts */
/* dtd dma address */
dma_addr_t dtd_dma;
/* next dtd virtual address */
struct langwell_dtd *next_dtd_virt;
};
/*
* dQH: Device Endpoint Queue Head
* describe where all transfers are managed
* 48-byte data structure, aligned on 64-byte boundary
*
* These are associated with dTD structure
*/
struct langwell_dqh {
/* endpoint capabilities and characteristics */
u32 dqh_res0:15; /* bits 14:0 */
u32 dqh_ios:1; /* bit 15, interrupt on setup */
#define DQH_IOS BIT(15)
u32 dqh_mpl:11; /* bits 26:16, maximum packet length */
#define DQH_MPL (0x7ff << 16)
u32 dqh_res1:2; /* bits 28:27 */
u32 dqh_zlt:1; /* bit 29, zero length termination */
#define DQH_ZLT BIT(29)
u32 dqh_mult:2; /* bits 31:30 */
#define DQH_MULT (BIT(30) | BIT(31))
/* current dTD pointer */
u32 dqh_current; /* locate the transfer in progress */
#define DQH_C_DTD(e) \
(((e)>>5)&0x7ffffff) /* bits 31:5, current dTD pointer */
/* transfer overlay, hardware parts of a struct langwell_dtd */
u32 dtd_next;
u32 dtd_status:8; /* bits 7:0, execution back states */
u32 dtd_res0:2; /* bits 9:8 */
u32 dtd_multo:2; /* bits 11:10, multipier override */
u32 dtd_res1:3; /* bits 14:12 */
u32 dtd_ioc:1; /* bit 15, interrupt on complete */
u32 dtd_total:15; /* bits 30:16, total bytes */
u32 dtd_res2:1; /* bit 31 */
u32 dtd_buf[5]; /* dTD buffer pointer page 0 to 4 */
u32 dqh_res2;
struct usb_ctrlrequest dqh_setup; /* setup packet buffer */
} __attribute__ ((aligned(64)));
/* endpoint data structure */
struct langwell_ep {
struct usb_ep ep;
dma_addr_t dma;
struct langwell_udc *dev;
unsigned long irqs;
struct list_head queue;
struct langwell_dqh *dqh;
const struct usb_endpoint_descriptor *desc;
char name[14];
unsigned stopped:1,
ep_type:2,
ep_num:8;
};
/* request data structure */
struct langwell_request {
struct usb_request req;
struct langwell_dtd *dtd, *head, *tail;
struct langwell_ep *ep;
dma_addr_t dtd_dma;
struct list_head queue;
unsigned dtd_count;
unsigned mapped:1;
};
/* ep0 transfer state */
enum ep0_state {
WAIT_FOR_SETUP,
DATA_STATE_XMIT,
DATA_STATE_NEED_ZLP,
WAIT_FOR_OUT_STATUS,
DATA_STATE_RECV,
};
/* device suspend state */
enum lpm_state {
LPM_L0, /* on */
LPM_L1, /* LPM L1 sleep */
LPM_L2, /* suspend */
LPM_L3, /* off */
};
/* device data structure */
struct langwell_udc {
/* each pci device provides one gadget, several endpoints */
struct usb_gadget gadget;
spinlock_t lock; /* device lock */
struct langwell_ep *ep;
struct usb_gadget_driver *driver;
struct otg_transceiver *transceiver;
u8 dev_addr;
u32 usb_state;
u32 resume_state;
u32 bus_reset;
enum lpm_state lpm_state;
enum ep0_state ep0_state;
u32 ep0_dir;
u16 dciversion;
unsigned ep_max;
unsigned devcap:1,
enabled:1,
region:1,
got_irq:1,
powered:1,
remote_wakeup:1,
rate:1,
is_reset:1,
softconnected:1,
vbus_active:1,
suspended:1,
stopped:1,
lpm:1; /* LPM capability */
/* pci state used to access those endpoints */
struct pci_dev *pdev;
/* Langwell otg transceiver */
struct langwell_otg *lotg;
/* control registers */
struct langwell_cap_regs __iomem *cap_regs;
struct langwell_op_regs __iomem *op_regs;
struct usb_ctrlrequest local_setup_buff;
struct langwell_dqh *ep_dqh;
size_t ep_dqh_size;
dma_addr_t ep_dqh_dma;
/* ep0 status request */
struct langwell_request *status_req;
/* dma pool */
struct dma_pool *dtd_pool;
/* make sure release() is done */
struct completion *done;
};

View File

@ -38,7 +38,6 @@
#include <linux/usb.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
#include <mach/pxa2xx-regs.h> /* FIXME: for PSSR */
#include <mach/udc.h>
#include "pxa27x_udc.h"
@ -473,6 +472,23 @@ static inline void udc_clear_mask_UDCCR(struct pxa_udc *udc, int mask)
(udccr & UDCCR_MASK_BITS) & ~(mask & UDCCR_MASK_BITS));
}
/**
* ep_write_UDCCSR - set bits in UDCCSR
* @udc: udc device
* @mask: bits to set in UDCCR
*
* Sets bits in UDCCSR (UDCCSR0 and UDCCSR*).
*
* A specific case is applied to ep0 : the ACM bit is always set to 1, for
* SET_INTERFACE and SET_CONFIGURATION.
*/
static inline void ep_write_UDCCSR(struct pxa_ep *ep, int mask)
{
if (is_ep0(ep))
mask |= UDCCSR0_ACM;
udc_ep_writel(ep, UDCCSR, mask);
}
/**
* ep_count_bytes_remain - get how many bytes in udc endpoint
* @ep: udc endpoint
@ -861,7 +877,7 @@ static int read_packet(struct pxa_ep *ep, struct pxa27x_request *req)
*buf++ = udc_ep_readl(ep, UDCDR);
req->req.actual += count;
udc_ep_writel(ep, UDCCSR, UDCCSR_PC);
ep_write_UDCCSR(ep, UDCCSR_PC);
return count;
}
@ -969,12 +985,12 @@ static int write_fifo(struct pxa_ep *ep, struct pxa27x_request *req)
if (udccsr & UDCCSR_PC) {
ep_vdbg(ep, "Clearing Transmit Complete, udccsr=%x\n",
udccsr);
udc_ep_writel(ep, UDCCSR, UDCCSR_PC);
ep_write_UDCCSR(ep, UDCCSR_PC);
}
if (udccsr & UDCCSR_TRN) {
ep_vdbg(ep, "Clearing Underrun on, udccsr=%x\n",
udccsr);
udc_ep_writel(ep, UDCCSR, UDCCSR_TRN);
ep_write_UDCCSR(ep, UDCCSR_TRN);
}
count = write_packet(ep, req, max);
@ -996,7 +1012,7 @@ static int write_fifo(struct pxa_ep *ep, struct pxa27x_request *req)
}
if (is_short)
udc_ep_writel(ep, UDCCSR, UDCCSR_SP);
ep_write_UDCCSR(ep, UDCCSR_SP);
/* requests complete when all IN data is in the FIFO */
if (is_last) {
@ -1029,7 +1045,7 @@ static int read_ep0_fifo(struct pxa_ep *ep, struct pxa27x_request *req)
while (epout_has_pkt(ep)) {
count = read_packet(ep, req);
udc_ep_writel(ep, UDCCSR, UDCCSR0_OPC);
ep_write_UDCCSR(ep, UDCCSR0_OPC);
inc_ep_stats_bytes(ep, count, !USB_DIR_IN);
is_short = (count < ep->fifo_size);
@ -1074,7 +1090,7 @@ static int write_ep0_fifo(struct pxa_ep *ep, struct pxa27x_request *req)
/* Sends either a short packet or a 0 length packet */
if (unlikely(is_short))
udc_ep_writel(ep, UDCCSR, UDCCSR0_IPR);
ep_write_UDCCSR(ep, UDCCSR0_IPR);
ep_dbg(ep, "in %d bytes%s%s, %d left, req=%p, udccsr0=0x%03x\n",
count, is_short ? "/S" : "", is_last ? "/L" : "",
@ -1277,7 +1293,7 @@ static int pxa_ep_set_halt(struct usb_ep *_ep, int value)
/* FST, FEF bits are the same for control and non control endpoints */
rc = 0;
udc_ep_writel(ep, UDCCSR, UDCCSR_FST | UDCCSR_FEF);
ep_write_UDCCSR(ep, UDCCSR_FST | UDCCSR_FEF);
if (is_ep0(ep))
set_ep0state(ep->dev, STALL);
@ -1343,7 +1359,7 @@ static void pxa_ep_fifo_flush(struct usb_ep *_ep)
udc_ep_readl(ep, UDCDR);
} else {
/* most IN status is the same, but ISO can't stall */
udc_ep_writel(ep, UDCCSR,
ep_write_UDCCSR(ep,
UDCCSR_PC | UDCCSR_FEF | UDCCSR_TRN
| (EPXFERTYPE_is_ISO(ep) ? 0 : UDCCSR_SST));
}
@ -1728,6 +1744,7 @@ static void udc_enable(struct pxa_udc *udc)
memset(&udc->stats, 0, sizeof(udc->stats));
udc_set_mask_UDCCR(udc, UDCCR_UDE);
ep_write_UDCCSR(&udc->pxa_ep[0], UDCCSR0_ACM);
udelay(2);
if (udc_readl(udc, UDCCR) & UDCCR_EMCE)
dev_err(udc->dev, "Configuration errors, udc disabled\n");
@ -1893,6 +1910,15 @@ static void handle_ep0_ctrl_req(struct pxa_udc *udc,
nuke(ep, -EPROTO);
/*
* In the PXA320 manual, in the section about Back-to-Back setup
* packets, it describes this situation. The solution is to set OPC to
* get rid of the status packet, and then continue with the setup
* packet. Generalize to pxa27x CPUs.
*/
if (epout_has_pkt(ep) && (ep_count_bytes_remain(ep) == 0))
ep_write_UDCCSR(ep, UDCCSR0_OPC);
/* read SETUP packet */
for (i = 0; i < 2; i++) {
if (unlikely(ep_is_empty(ep)))
@ -1919,7 +1945,7 @@ static void handle_ep0_ctrl_req(struct pxa_udc *udc,
set_ep0state(udc, OUT_DATA_STAGE);
/* Tell UDC to enter Data Stage */
udc_ep_writel(ep, UDCCSR, UDCCSR0_SA | UDCCSR0_OPC);
ep_write_UDCCSR(ep, UDCCSR0_SA | UDCCSR0_OPC);
i = udc->driver->setup(&udc->gadget, &u.r);
if (i < 0)
@ -1929,7 +1955,7 @@ out:
stall:
ep_dbg(ep, "protocol STALL, udccsr0=%03x err %d\n",
udc_ep_readl(ep, UDCCSR), i);
udc_ep_writel(ep, UDCCSR, UDCCSR0_FST | UDCCSR0_FTF);
ep_write_UDCCSR(ep, UDCCSR0_FST | UDCCSR0_FTF);
set_ep0state(udc, STALL);
goto out;
}
@ -1966,6 +1992,8 @@ stall:
* cleared by software.
* - clearing UDCCSR0_OPC always flushes ep0. If in setup stage, never do it
* before reading ep0.
* This is true only for PXA27x. This is not true anymore for PXA3xx family
* (check Back-to-Back setup packet in developers guide).
* - irq can be called on a "packet complete" event (opc_irq=1), while
* UDCCSR0_OPC is not yet raised (delta can be as big as 100ms
* from experimentation).
@ -1998,7 +2026,7 @@ static void handle_ep0(struct pxa_udc *udc, int fifo_irq, int opc_irq)
if (udccsr0 & UDCCSR0_SST) {
ep_dbg(ep, "clearing stall status\n");
nuke(ep, -EPIPE);
udc_ep_writel(ep, UDCCSR, UDCCSR0_SST);
ep_write_UDCCSR(ep, UDCCSR0_SST);
ep0_idle(udc);
}
@ -2023,7 +2051,7 @@ static void handle_ep0(struct pxa_udc *udc, int fifo_irq, int opc_irq)
break;
case IN_DATA_STAGE: /* GET_DESCRIPTOR */
if (epout_has_pkt(ep))
udc_ep_writel(ep, UDCCSR, UDCCSR0_OPC);
ep_write_UDCCSR(ep, UDCCSR0_OPC);
if (req && !ep_is_full(ep))
completed = write_ep0_fifo(ep, req);
if (completed)
@ -2036,7 +2064,7 @@ static void handle_ep0(struct pxa_udc *udc, int fifo_irq, int opc_irq)
ep0_end_out_req(ep, req);
break;
case STALL:
udc_ep_writel(ep, UDCCSR, UDCCSR0_FST);
ep_write_UDCCSR(ep, UDCCSR0_FST);
break;
case IN_STATUS_STAGE:
/*
@ -2131,6 +2159,7 @@ static void pxa27x_change_configuration(struct pxa_udc *udc, int config)
set_ep0state(udc, WAIT_ACK_SET_CONF_INTERF);
udc->driver->setup(&udc->gadget, &req);
ep_write_UDCCSR(&udc->pxa_ep[0], UDCCSR0_AREN);
}
/**
@ -2159,6 +2188,7 @@ static void pxa27x_change_interface(struct pxa_udc *udc, int iface, int alt)
set_ep0state(udc, WAIT_ACK_SET_CONF_INTERF);
udc->driver->setup(&udc->gadget, &req);
ep_write_UDCCSR(&udc->pxa_ep[0], UDCCSR0_AREN);
}
/*
@ -2280,7 +2310,7 @@ static void irq_udc_reset(struct pxa_udc *udc)
memset(&udc->stats, 0, sizeof udc->stats);
nuke(ep, -EPROTO);
udc_ep_writel(ep, UDCCSR, UDCCSR0_FTF | UDCCSR0_OPC);
ep_write_UDCCSR(ep, UDCCSR0_FTF | UDCCSR0_OPC);
ep0_idle(udc);
}
@ -2479,6 +2509,12 @@ static void pxa_udc_shutdown(struct platform_device *_dev)
udc_disable(udc);
}
#ifdef CONFIG_CPU_PXA27x
extern void pxa27x_clear_otgph(void);
#else
#define pxa27x_clear_otgph() do {} while (0)
#endif
#ifdef CONFIG_PM
/**
* pxa_udc_suspend - Suspend udc device
@ -2546,8 +2582,7 @@ static int pxa_udc_resume(struct platform_device *_dev)
* Software must configure the USB OTG pad, UDC, and UHC
* to the state they were in before entering sleep mode.
*/
if (cpu_is_pxa27x())
PSSR |= PSSR_OTGPH;
pxa27x_clear_otgph();
return 0;
}
@ -2571,7 +2606,7 @@ static struct platform_driver udc_driver = {
static int __init udc_init(void)
{
if (!cpu_is_pxa27x())
if (!cpu_is_pxa27x() && !cpu_is_pxa3xx())
return -ENODEV;
printk(KERN_INFO "%s: version %s\n", driver_name, DRIVER_VERSION);

View File

@ -130,6 +130,8 @@
#define UP2OCR_HXOE (1 << 17) /* Transceiver Output Enable */
#define UP2OCR_SEOS (1 << 24) /* Single-Ended Output Select */
#define UDCCSR0_ACM (1 << 9) /* Ack Control Mode */
#define UDCCSR0_AREN (1 << 8) /* Ack Response Enable */
#define UDCCSR0_SA (1 << 7) /* Setup Active */
#define UDCCSR0_RNE (1 << 6) /* Receive FIFO Not Empty */
#define UDCCSR0_FST (1 << 5) /* Force Stall */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,319 @@
/*
* u_audio.c -- ALSA audio utilities for Gadget stack
*
* Copyright (C) 2008 Bryan Wu <cooloney@kernel.org>
* Copyright (C) 2008 Analog Devices, Inc
*
* Enter bugs at http://blackfin.uclinux.org/
*
* Licensed under the GPL-2 or later.
*/
#include <linux/kernel.h>
#include <linux/utsname.h>
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/ctype.h>
#include <linux/random.h>
#include <linux/syscalls.h>
#include "u_audio.h"
/*
* This component encapsulates the ALSA devices for USB audio gadget
*/
#define FILE_PCM_PLAYBACK "/dev/snd/pcmC0D0p"
#define FILE_PCM_CAPTURE "/dev/snd/pcmC0D0c"
#define FILE_CONTROL "/dev/snd/controlC0"
static char *fn_play = FILE_PCM_PLAYBACK;
module_param(fn_play, charp, S_IRUGO);
MODULE_PARM_DESC(fn_play, "Playback PCM device file name");
static char *fn_cap = FILE_PCM_CAPTURE;
module_param(fn_cap, charp, S_IRUGO);
MODULE_PARM_DESC(fn_cap, "Capture PCM device file name");
static char *fn_cntl = FILE_CONTROL;
module_param(fn_cntl, charp, S_IRUGO);
MODULE_PARM_DESC(fn_cntl, "Control device file name");
/*-------------------------------------------------------------------------*/
/**
* Some ALSA internal helper functions
*/
static int snd_interval_refine_set(struct snd_interval *i, unsigned int val)
{
struct snd_interval t;
t.empty = 0;
t.min = t.max = val;
t.openmin = t.openmax = 0;
t.integer = 1;
return snd_interval_refine(i, &t);
}
static int _snd_pcm_hw_param_set(struct snd_pcm_hw_params *params,
snd_pcm_hw_param_t var, unsigned int val,
int dir)
{
int changed;
if (hw_is_mask(var)) {
struct snd_mask *m = hw_param_mask(params, var);
if (val == 0 && dir < 0) {
changed = -EINVAL;
snd_mask_none(m);
} else {
if (dir > 0)
val++;
else if (dir < 0)
val--;
changed = snd_mask_refine_set(
hw_param_mask(params, var), val);
}
} else if (hw_is_interval(var)) {
struct snd_interval *i = hw_param_interval(params, var);
if (val == 0 && dir < 0) {
changed = -EINVAL;
snd_interval_none(i);
} else if (dir == 0)
changed = snd_interval_refine_set(i, val);
else {
struct snd_interval t;
t.openmin = 1;
t.openmax = 1;
t.empty = 0;
t.integer = 0;
if (dir < 0) {
t.min = val - 1;
t.max = val;
} else {
t.min = val;
t.max = val+1;
}
changed = snd_interval_refine(i, &t);
}
} else
return -EINVAL;
if (changed) {
params->cmask |= 1 << var;
params->rmask |= 1 << var;
}
return changed;
}
/*-------------------------------------------------------------------------*/
/**
* Set default hardware params
*/
static int playback_default_hw_params(struct gaudio_snd_dev *snd)
{
struct snd_pcm_substream *substream = snd->substream;
struct snd_pcm_hw_params *params;
snd_pcm_sframes_t result;
/*
* SNDRV_PCM_ACCESS_RW_INTERLEAVED,
* SNDRV_PCM_FORMAT_S16_LE
* CHANNELS: 2
* RATE: 48000
*/
snd->access = SNDRV_PCM_ACCESS_RW_INTERLEAVED;
snd->format = SNDRV_PCM_FORMAT_S16_LE;
snd->channels = 2;
snd->rate = 48000;
params = kzalloc(sizeof(*params), GFP_KERNEL);
if (!params)
return -ENOMEM;
_snd_pcm_hw_params_any(params);
_snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_ACCESS,
snd->access, 0);
_snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_FORMAT,
snd->format, 0);
_snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_CHANNELS,
snd->channels, 0);
_snd_pcm_hw_param_set(params, SNDRV_PCM_HW_PARAM_RATE,
snd->rate, 0);
snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_HW_PARAMS, params);
result = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_PREPARE, NULL);
if (result < 0) {
ERROR(snd->card,
"Preparing sound card failed: %d\n", (int)result);
kfree(params);
return result;
}
/* Store the hardware parameters */
snd->access = params_access(params);
snd->format = params_format(params);
snd->channels = params_channels(params);
snd->rate = params_rate(params);
kfree(params);
INFO(snd->card,
"Hardware params: access %x, format %x, channels %d, rate %d\n",
snd->access, snd->format, snd->channels, snd->rate);
return 0;
}
/**
* Playback audio buffer data by ALSA PCM device
*/
static size_t u_audio_playback(struct gaudio *card, void *buf, size_t count)
{
struct gaudio_snd_dev *snd = &card->playback;
struct snd_pcm_substream *substream = snd->substream;
struct snd_pcm_runtime *runtime = substream->runtime;
mm_segment_t old_fs;
ssize_t result;
snd_pcm_sframes_t frames;
try_again:
if (runtime->status->state == SNDRV_PCM_STATE_XRUN ||
runtime->status->state == SNDRV_PCM_STATE_SUSPENDED) {
result = snd_pcm_kernel_ioctl(substream,
SNDRV_PCM_IOCTL_PREPARE, NULL);
if (result < 0) {
ERROR(card, "Preparing sound card failed: %d\n",
(int)result);
return result;
}
}
frames = bytes_to_frames(runtime, count);
old_fs = get_fs();
set_fs(KERNEL_DS);
result = snd_pcm_lib_write(snd->substream, buf, frames);
if (result != frames) {
ERROR(card, "Playback error: %d\n", (int)result);
set_fs(old_fs);
goto try_again;
}
set_fs(old_fs);
return 0;
}
static int u_audio_get_playback_channels(struct gaudio *card)
{
return card->playback.channels;
}
static int u_audio_get_playback_rate(struct gaudio *card)
{
return card->playback.rate;
}
/**
* Open ALSA PCM and control device files
* Initial the PCM or control device
*/
static int gaudio_open_snd_dev(struct gaudio *card)
{
struct snd_pcm_file *pcm_file;
struct gaudio_snd_dev *snd;
if (!card)
return -ENODEV;
/* Open control device */
snd = &card->control;
snd->filp = filp_open(fn_cntl, O_RDWR, 0);
if (IS_ERR(snd->filp)) {
int ret = PTR_ERR(snd->filp);
ERROR(card, "unable to open sound control device file: %s\n",
fn_cntl);
snd->filp = NULL;
return ret;
}
snd->card = card;
/* Open PCM playback device and setup substream */
snd = &card->playback;
snd->filp = filp_open(fn_play, O_WRONLY, 0);
if (IS_ERR(snd->filp)) {
ERROR(card, "No such PCM playback device: %s\n", fn_play);
snd->filp = NULL;
}
pcm_file = snd->filp->private_data;
snd->substream = pcm_file->substream;
snd->card = card;
playback_default_hw_params(snd);
/* Open PCM capture device and setup substream */
snd = &card->capture;
snd->filp = filp_open(fn_cap, O_RDONLY, 0);
if (IS_ERR(snd->filp)) {
ERROR(card, "No such PCM capture device: %s\n", fn_cap);
snd->filp = NULL;
}
pcm_file = snd->filp->private_data;
snd->substream = pcm_file->substream;
snd->card = card;
return 0;
}
/**
* Close ALSA PCM and control device files
*/
static int gaudio_close_snd_dev(struct gaudio *gau)
{
struct gaudio_snd_dev *snd;
/* Close control device */
snd = &gau->control;
if (!IS_ERR(snd->filp))
filp_close(snd->filp, current->files);
/* Close PCM playback device and setup substream */
snd = &gau->playback;
if (!IS_ERR(snd->filp))
filp_close(snd->filp, current->files);
/* Close PCM capture device and setup substream */
snd = &gau->capture;
if (!IS_ERR(snd->filp))
filp_close(snd->filp, current->files);
return 0;
}
/**
* gaudio_setup - setup ALSA interface and preparing for USB transfer
*
* This sets up PCM, mixer or MIDI ALSA devices fore USB gadget using.
*
* Returns negative errno, or zero on success
*/
int __init gaudio_setup(struct gaudio *card)
{
int ret;
ret = gaudio_open_snd_dev(card);
if (ret)
ERROR(card, "we need at least one control device\n");
return ret;
}
/**
* gaudio_cleanup - remove ALSA device interface
*
* This is called to free all resources allocated by @gaudio_setup().
*/
void gaudio_cleanup(struct gaudio *card)
{
if (card)
gaudio_close_snd_dev(card);
}

View File

@ -0,0 +1,56 @@
/*
* u_audio.h -- interface to USB gadget "ALSA AUDIO" utilities
*
* Copyright (C) 2008 Bryan Wu <cooloney@kernel.org>
* Copyright (C) 2008 Analog Devices, Inc
*
* Enter bugs at http://blackfin.uclinux.org/
*
* Licensed under the GPL-2 or later.
*/
#ifndef __U_AUDIO_H
#define __U_AUDIO_H
#include <linux/device.h>
#include <linux/err.h>
#include <linux/usb/audio.h>
#include <linux/usb/composite.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include "gadget_chips.h"
/*
* This represents the USB side of an audio card device, managed by a USB
* function which provides control and stream interfaces.
*/
struct gaudio_snd_dev {
struct gaudio *card;
struct file *filp;
struct snd_pcm_substream *substream;
int access;
int format;
int channels;
int rate;
};
struct gaudio {
struct usb_function func;
struct usb_gadget *gadget;
/* ALSA sound device interfaces */
struct gaudio_snd_dev control;
struct gaudio_snd_dev playback;
struct gaudio_snd_dev capture;
/* TODO */
};
int gaudio_setup(struct gaudio *card);
void gaudio_cleanup(struct gaudio *card);
#endif /* __U_AUDIO_H */

View File

@ -371,6 +371,7 @@ __acquires(&port->port_lock)
req->length = len;
list_del(&req->list);
req->zero = (gs_buf_data_avail(&port->port_write_buf) == 0);
pr_vdebug(PREFIX "%d: tx len=%d, 0x%02x 0x%02x 0x%02x ...\n",
port->port_num, len, *((u8 *)req->buf),

View File

@ -17,6 +17,26 @@ config USB_C67X00_HCD
To compile this driver as a module, choose M here: the
module will be called c67x00.
config USB_XHCI_HCD
tristate "xHCI HCD (USB 3.0) support (EXPERIMENTAL)"
depends on USB && PCI && EXPERIMENTAL
---help---
The eXtensible Host Controller Interface (xHCI) is standard for USB 3.0
"SuperSpeed" host controller hardware.
To compile this driver as a module, choose M here: the
module will be called xhci-hcd.
config USB_XHCI_HCD_DEBUGGING
bool "Debugging for the xHCI host controller"
depends on USB_XHCI_HCD
---help---
Say 'Y' to turn on debugging for the xHCI host controller driver.
This will spew debugging output, even in interrupt context.
This should only be used for debugging xHCI driver bugs.
If unsure, say N.
config USB_EHCI_HCD
tristate "EHCI HCD (USB 2.0) support"
depends on USB && USB_ARCH_HAS_EHCI

View File

@ -12,6 +12,7 @@ fhci-objs := fhci-hcd.o fhci-hub.o fhci-q.o fhci-mem.o \
ifeq ($(CONFIG_FHCI_DEBUG),y)
fhci-objs += fhci-dbg.o
endif
xhci-objs := xhci-hcd.o xhci-mem.o xhci-pci.o xhci-ring.o xhci-hub.o xhci-dbg.o
obj-$(CONFIG_USB_WHCI_HCD) += whci/
@ -23,6 +24,7 @@ obj-$(CONFIG_USB_ISP116X_HCD) += isp116x-hcd.o
obj-$(CONFIG_USB_OHCI_HCD) += ohci-hcd.o
obj-$(CONFIG_USB_UHCI_HCD) += uhci-hcd.o
obj-$(CONFIG_USB_FHCI_HCD) += fhci.o
obj-$(CONFIG_USB_XHCI_HCD) += xhci.o
obj-$(CONFIG_USB_SL811_HCD) += sl811-hcd.o
obj-$(CONFIG_USB_SL811_CS) += sl811_cs.o
obj-$(CONFIG_USB_U132_HCD) += u132-hcd.o

View File

@ -97,6 +97,7 @@ static const struct hc_driver ehci_au1xxx_hc_driver = {
.urb_enqueue = ehci_urb_enqueue,
.urb_dequeue = ehci_urb_dequeue,
.endpoint_disable = ehci_endpoint_disable,
.endpoint_reset = ehci_endpoint_reset,
/*
* scheduling support

View File

@ -309,6 +309,7 @@ static const struct hc_driver ehci_fsl_hc_driver = {
.urb_enqueue = ehci_urb_enqueue,
.urb_dequeue = ehci_urb_dequeue,
.endpoint_disable = ehci_endpoint_disable,
.endpoint_reset = ehci_endpoint_reset,
/*
* scheduling support

View File

@ -1024,6 +1024,51 @@ done:
return;
}
static void
ehci_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
{
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
struct ehci_qh *qh;
int eptype = usb_endpoint_type(&ep->desc);
if (eptype != USB_ENDPOINT_XFER_BULK && eptype != USB_ENDPOINT_XFER_INT)
return;
rescan:
spin_lock_irq(&ehci->lock);
qh = ep->hcpriv;
/* For Bulk and Interrupt endpoints we maintain the toggle state
* in the hardware; the toggle bits in udev aren't used at all.
* When an endpoint is reset by usb_clear_halt() we must reset
* the toggle bit in the QH.
*/
if (qh) {
if (!list_empty(&qh->qtd_list)) {
WARN_ONCE(1, "clear_halt for a busy endpoint\n");
} else if (qh->qh_state == QH_STATE_IDLE) {
qh->hw_token &= ~cpu_to_hc32(ehci, QTD_TOGGLE);
} else {
/* It's not safe to write into the overlay area
* while the QH is active. Unlink it first and
* wait for the unlink to complete.
*/
if (qh->qh_state == QH_STATE_LINKED) {
if (eptype == USB_ENDPOINT_XFER_BULK) {
unlink_async(ehci, qh);
} else {
intr_deschedule(ehci, qh);
(void) qh_schedule(ehci, qh);
}
}
spin_unlock_irq(&ehci->lock);
schedule_timeout_uninterruptible(1);
goto rescan;
}
}
spin_unlock_irq(&ehci->lock);
}
static int ehci_get_frame (struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
@ -1097,7 +1142,7 @@ static int __init ehci_hcd_init(void)
sizeof(struct ehci_itd), sizeof(struct ehci_sitd));
#ifdef DEBUG
ehci_debug_root = debugfs_create_dir("ehci", NULL);
ehci_debug_root = debugfs_create_dir("ehci", usb_debug_root);
if (!ehci_debug_root) {
retval = -ENOENT;
goto err_debug;

View File

@ -391,7 +391,7 @@ static inline void create_companion_file(struct ehci_hcd *ehci)
/* with integrated TT there is no companion! */
if (!ehci_is_TDI(ehci))
i = device_create_file(ehci_to_hcd(ehci)->self.dev,
i = device_create_file(ehci_to_hcd(ehci)->self.controller,
&dev_attr_companion);
}
@ -399,7 +399,7 @@ static inline void remove_companion_file(struct ehci_hcd *ehci)
{
/* with integrated TT there is no companion! */
if (!ehci_is_TDI(ehci))
device_remove_file(ehci_to_hcd(ehci)->self.dev,
device_remove_file(ehci_to_hcd(ehci)->self.controller,
&dev_attr_companion);
}

View File

@ -51,6 +51,7 @@ static const struct hc_driver ixp4xx_ehci_hc_driver = {
.urb_enqueue = ehci_urb_enqueue,
.urb_dequeue = ehci_urb_dequeue,
.endpoint_disable = ehci_endpoint_disable,
.endpoint_reset = ehci_endpoint_reset,
.get_frame_number = ehci_get_frame,
.hub_status_data = ehci_hub_status_data,
.hub_control = ehci_hub_control,

View File

@ -149,6 +149,7 @@ static const struct hc_driver ehci_orion_hc_driver = {
.urb_enqueue = ehci_urb_enqueue,
.urb_dequeue = ehci_urb_dequeue,
.endpoint_disable = ehci_endpoint_disable,
.endpoint_reset = ehci_endpoint_reset,
/*
* scheduling support
@ -187,7 +188,7 @@ ehci_orion_conf_mbus_windows(struct usb_hcd *hcd,
}
}
static int __init ehci_orion_drv_probe(struct platform_device *pdev)
static int __devinit ehci_orion_drv_probe(struct platform_device *pdev)
{
struct orion_ehci_data *pd = pdev->dev.platform_data;
struct resource *res;

View File

@ -268,7 +268,7 @@ done:
* Also they depend on separate root hub suspend/resume.
*/
static int ehci_pci_suspend(struct usb_hcd *hcd, pm_message_t message)
static int ehci_pci_suspend(struct usb_hcd *hcd)
{
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
unsigned long flags;
@ -293,12 +293,6 @@ static int ehci_pci_suspend(struct usb_hcd *hcd, pm_message_t message)
ehci_writel(ehci, 0, &ehci->regs->intr_enable);
(void)ehci_readl(ehci, &ehci->regs->intr_enable);
/* make sure snapshot being resumed re-enumerates everything */
if (message.event == PM_EVENT_PRETHAW) {
ehci_halt(ehci);
ehci_reset(ehci);
}
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
bail:
spin_unlock_irqrestore (&ehci->lock, flags);
@ -309,7 +303,7 @@ static int ehci_pci_suspend(struct usb_hcd *hcd, pm_message_t message)
return rc;
}
static int ehci_pci_resume(struct usb_hcd *hcd)
static int ehci_pci_resume(struct usb_hcd *hcd, bool hibernated)
{
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
@ -322,10 +316,12 @@ static int ehci_pci_resume(struct usb_hcd *hcd)
/* Mark hardware accessible again as we are out of D3 state by now */
set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
/* If CF is still set, we maintained PCI Vaux power.
/* If CF is still set and we aren't resuming from hibernation
* then we maintained PCI Vaux power.
* Just undo the effect of ehci_pci_suspend().
*/
if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF) {
if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF &&
!hibernated) {
int mask = INTR_MASK;
if (!hcd->self.root_hub->do_remote_wakeup)
@ -335,7 +331,6 @@ static int ehci_pci_resume(struct usb_hcd *hcd)
return 0;
}
ehci_dbg(ehci, "lost power, restarting\n");
usb_root_hub_lost_power(hcd->self.root_hub);
/* Else reset, to cope with power loss or flush-to-storage
@ -393,6 +388,7 @@ static const struct hc_driver ehci_pci_hc_driver = {
.urb_enqueue = ehci_urb_enqueue,
.urb_dequeue = ehci_urb_dequeue,
.endpoint_disable = ehci_endpoint_disable,
.endpoint_reset = ehci_endpoint_reset,
/*
* scheduling support
@ -429,10 +425,11 @@ static struct pci_driver ehci_pci_driver = {
.probe = usb_hcd_pci_probe,
.remove = usb_hcd_pci_remove,
#ifdef CONFIG_PM
.suspend = usb_hcd_pci_suspend,
.resume = usb_hcd_pci_resume,
#endif
.shutdown = usb_hcd_pci_shutdown,
#ifdef CONFIG_PM_SLEEP
.driver = {
.pm = &usb_hcd_pci_pm_ops
},
#endif
};

View File

@ -61,6 +61,7 @@ static const struct hc_driver ehci_ppc_of_hc_driver = {
.urb_enqueue = ehci_urb_enqueue,
.urb_dequeue = ehci_urb_dequeue,
.endpoint_disable = ehci_endpoint_disable,
.endpoint_reset = ehci_endpoint_reset,
/*
* scheduling support

View File

@ -65,6 +65,7 @@ static const struct hc_driver ps3_ehci_hc_driver = {
.urb_enqueue = ehci_urb_enqueue,
.urb_dequeue = ehci_urb_dequeue,
.endpoint_disable = ehci_endpoint_disable,
.endpoint_reset = ehci_endpoint_reset,
.get_frame_number = ehci_get_frame,
.hub_status_data = ehci_hub_status_data,
.hub_control = ehci_hub_control,

View File

@ -93,22 +93,6 @@ qh_update (struct ehci_hcd *ehci, struct ehci_qh *qh, struct ehci_qtd *qtd)
qh->hw_qtd_next = QTD_NEXT(ehci, qtd->qtd_dma);
qh->hw_alt_next = EHCI_LIST_END(ehci);
/* Except for control endpoints, we make hardware maintain data
* toggle (like OHCI) ... here (re)initialize the toggle in the QH,
* and set the pseudo-toggle in udev. Only usb_clear_halt() will
* ever clear it.
*/
if (!(qh->hw_info1 & cpu_to_hc32(ehci, 1 << 14))) {
unsigned is_out, epnum;
is_out = !(qtd->hw_token & cpu_to_hc32(ehci, 1 << 8));
epnum = (hc32_to_cpup(ehci, &qh->hw_info1) >> 8) & 0x0f;
if (unlikely (!usb_gettoggle (qh->dev, epnum, is_out))) {
qh->hw_token &= ~cpu_to_hc32(ehci, QTD_TOGGLE);
usb_settoggle (qh->dev, epnum, is_out, 1);
}
}
/* HC must see latest qtd and qh data before we clear ACTIVE+HALT */
wmb ();
qh->hw_token &= cpu_to_hc32(ehci, QTD_TOGGLE | QTD_STS_PING);
@ -850,7 +834,6 @@ done:
qh->qh_state = QH_STATE_IDLE;
qh->hw_info1 = cpu_to_hc32(ehci, info1);
qh->hw_info2 = cpu_to_hc32(ehci, info2);
usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), !is_input, 1);
qh_refresh (ehci, qh);
return qh;
}
@ -881,7 +864,7 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
}
}
/* clear halt and/or toggle; and maybe recover from silicon quirk */
/* clear halt and maybe recover from silicon quirk */
if (qh->qh_state == QH_STATE_IDLE)
qh_refresh (ehci, qh);

View File

@ -760,8 +760,10 @@ static int qh_schedule(struct ehci_hcd *ehci, struct ehci_qh *qh)
if (status) {
/* "normal" case, uframing flexible except with splits */
if (qh->period) {
frame = qh->period - 1;
do {
int i;
for (i = qh->period; status && i > 0; --i) {
frame = ++ehci->random_frame % qh->period;
for (uframe = 0; uframe < 8; uframe++) {
status = check_intr_schedule (ehci,
frame, uframe, qh,
@ -769,7 +771,7 @@ static int qh_schedule(struct ehci_hcd *ehci, struct ehci_qh *qh)
if (status == 0)
break;
}
} while (status && frame--);
}
/* qh->period == 0 means every uframe */
} else {

View File

@ -116,6 +116,7 @@ struct ehci_hcd { /* one per controller */
struct timer_list watchdog;
unsigned long actions;
unsigned stamp;
unsigned random_frame;
unsigned long next_statechange;
u32 command;

View File

@ -108,7 +108,7 @@ void fhci_dfs_create(struct fhci_hcd *fhci)
{
struct device *dev = fhci_to_hcd(fhci)->self.controller;
fhci->dfs_root = debugfs_create_dir(dev_name(dev), NULL);
fhci->dfs_root = debugfs_create_dir(dev_name(dev), usb_debug_root);
if (!fhci->dfs_root) {
WARN_ON(1);
return;

View File

@ -172,25 +172,6 @@ error_cluster_id_get:
}
static int hwahc_op_suspend(struct usb_hcd *usb_hcd, pm_message_t msg)
{
struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
dev_err(wusbhc->dev, "%s (%p [%p], 0x%lx) UNIMPLEMENTED\n", __func__,
usb_hcd, hwahc, *(unsigned long *) &msg);
return -ENOSYS;
}
static int hwahc_op_resume(struct usb_hcd *usb_hcd)
{
struct wusbhc *wusbhc = usb_hcd_to_wusbhc(usb_hcd);
struct hwahc *hwahc = container_of(wusbhc, struct hwahc, wusbhc);
dev_err(wusbhc->dev, "%s (%p [%p]) UNIMPLEMENTED\n", __func__,
usb_hcd, hwahc);
return -ENOSYS;
}
/*
* No need to abort pipes, as when this is called, all the children
* has been disconnected and that has done it [through
@ -598,8 +579,6 @@ static struct hc_driver hwahc_hc_driver = {
.flags = HCD_USB2, /* FIXME */
.reset = hwahc_op_reset,
.start = hwahc_op_start,
.pci_suspend = hwahc_op_suspend,
.pci_resume = hwahc_op_resume,
.stop = hwahc_op_stop,
.get_frame_number = hwahc_op_get_frame_number,
.urb_enqueue = hwahc_op_urb_enqueue,

View File

@ -431,7 +431,7 @@ static struct dentry *ohci_debug_root;
struct debug_buffer {
ssize_t (*fill_func)(struct debug_buffer *); /* fill method */
struct device *dev;
struct ohci_hcd *ohci;
struct mutex mutex; /* protect filling of buffer */
size_t count; /* number of characters filled into buffer */
char *page;
@ -505,15 +505,11 @@ show_list (struct ohci_hcd *ohci, char *buf, size_t count, struct ed *ed)
static ssize_t fill_async_buffer(struct debug_buffer *buf)
{
struct usb_bus *bus;
struct usb_hcd *hcd;
struct ohci_hcd *ohci;
size_t temp;
unsigned long flags;
bus = dev_get_drvdata(buf->dev);
hcd = bus_to_hcd(bus);
ohci = hcd_to_ohci(hcd);
ohci = buf->ohci;
/* display control and bulk lists together, for simplicity */
spin_lock_irqsave (&ohci->lock, flags);
@ -529,8 +525,6 @@ static ssize_t fill_async_buffer(struct debug_buffer *buf)
static ssize_t fill_periodic_buffer(struct debug_buffer *buf)
{
struct usb_bus *bus;
struct usb_hcd *hcd;
struct ohci_hcd *ohci;
struct ed **seen, *ed;
unsigned long flags;
@ -542,9 +536,7 @@ static ssize_t fill_periodic_buffer(struct debug_buffer *buf)
return 0;
seen_count = 0;
bus = (struct usb_bus *)dev_get_drvdata(buf->dev);
hcd = bus_to_hcd(bus);
ohci = hcd_to_ohci(hcd);
ohci = buf->ohci;
next = buf->page;
size = PAGE_SIZE;
@ -626,7 +618,6 @@ static ssize_t fill_periodic_buffer(struct debug_buffer *buf)
static ssize_t fill_registers_buffer(struct debug_buffer *buf)
{
struct usb_bus *bus;
struct usb_hcd *hcd;
struct ohci_hcd *ohci;
struct ohci_regs __iomem *regs;
@ -635,9 +626,8 @@ static ssize_t fill_registers_buffer(struct debug_buffer *buf)
char *next;
u32 rdata;
bus = (struct usb_bus *)dev_get_drvdata(buf->dev);
hcd = bus_to_hcd(bus);
ohci = hcd_to_ohci(hcd);
ohci = buf->ohci;
hcd = ohci_to_hcd(ohci);
regs = ohci->regs;
next = buf->page;
size = PAGE_SIZE;
@ -710,7 +700,7 @@ done:
return PAGE_SIZE - size;
}
static struct debug_buffer *alloc_buffer(struct device *dev,
static struct debug_buffer *alloc_buffer(struct ohci_hcd *ohci,
ssize_t (*fill_func)(struct debug_buffer *))
{
struct debug_buffer *buf;
@ -718,7 +708,7 @@ static struct debug_buffer *alloc_buffer(struct device *dev,
buf = kzalloc(sizeof(struct debug_buffer), GFP_KERNEL);
if (buf) {
buf->dev = dev;
buf->ohci = ohci;
buf->fill_func = fill_func;
mutex_init(&buf->mutex);
}
@ -810,26 +800,25 @@ static int debug_registers_open(struct inode *inode, struct file *file)
static inline void create_debug_files (struct ohci_hcd *ohci)
{
struct usb_bus *bus = &ohci_to_hcd(ohci)->self;
struct device *dev = bus->dev;
ohci->debug_dir = debugfs_create_dir(bus->bus_name, ohci_debug_root);
if (!ohci->debug_dir)
goto dir_error;
ohci->debug_async = debugfs_create_file("async", S_IRUGO,
ohci->debug_dir, dev,
ohci->debug_dir, ohci,
&debug_async_fops);
if (!ohci->debug_async)
goto async_error;
ohci->debug_periodic = debugfs_create_file("periodic", S_IRUGO,
ohci->debug_dir, dev,
ohci->debug_dir, ohci,
&debug_periodic_fops);
if (!ohci->debug_periodic)
goto periodic_error;
ohci->debug_registers = debugfs_create_file("registers", S_IRUGO,
ohci->debug_dir, dev,
ohci->debug_dir, ohci,
&debug_registers_fops);
if (!ohci->debug_registers)
goto registers_error;

View File

@ -571,7 +571,7 @@ static int ohci_init (struct ohci_hcd *ohci)
*/
static int ohci_run (struct ohci_hcd *ohci)
{
u32 mask, temp;
u32 mask, val;
int first = ohci->fminterval == 0;
struct usb_hcd *hcd = ohci_to_hcd(ohci);
@ -580,8 +580,8 @@ static int ohci_run (struct ohci_hcd *ohci)
/* boot firmware should have set this up (5.1.1.3.1) */
if (first) {
temp = ohci_readl (ohci, &ohci->regs->fminterval);
ohci->fminterval = temp & 0x3fff;
val = ohci_readl (ohci, &ohci->regs->fminterval);
ohci->fminterval = val & 0x3fff;
if (ohci->fminterval != FI)
ohci_dbg (ohci, "fminterval delta %d\n",
ohci->fminterval - FI);
@ -600,25 +600,25 @@ static int ohci_run (struct ohci_hcd *ohci)
switch (ohci->hc_control & OHCI_CTRL_HCFS) {
case OHCI_USB_OPER:
temp = 0;
val = 0;
break;
case OHCI_USB_SUSPEND:
case OHCI_USB_RESUME:
ohci->hc_control &= OHCI_CTRL_RWC;
ohci->hc_control |= OHCI_USB_RESUME;
temp = 10 /* msec wait */;
val = 10 /* msec wait */;
break;
// case OHCI_USB_RESET:
default:
ohci->hc_control &= OHCI_CTRL_RWC;
ohci->hc_control |= OHCI_USB_RESET;
temp = 50 /* msec wait */;
val = 50 /* msec wait */;
break;
}
ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
// flush the writes
(void) ohci_readl (ohci, &ohci->regs->control);
msleep(temp);
msleep(val);
memset (ohci->hcca, 0, sizeof (struct ohci_hcca));
@ -628,9 +628,9 @@ static int ohci_run (struct ohci_hcd *ohci)
retry:
/* HC Reset requires max 10 us delay */
ohci_writel (ohci, OHCI_HCR, &ohci->regs->cmdstatus);
temp = 30; /* ... allow extra time */
val = 30; /* ... allow extra time */
while ((ohci_readl (ohci, &ohci->regs->cmdstatus) & OHCI_HCR) != 0) {
if (--temp == 0) {
if (--val == 0) {
spin_unlock_irq (&ohci->lock);
ohci_err (ohci, "USB HC reset timed out!\n");
return -1;
@ -699,23 +699,23 @@ retry:
ohci_writel (ohci, mask, &ohci->regs->intrenable);
/* handle root hub init quirks ... */
temp = roothub_a (ohci);
temp &= ~(RH_A_PSM | RH_A_OCPM);
val = roothub_a (ohci);
val &= ~(RH_A_PSM | RH_A_OCPM);
if (ohci->flags & OHCI_QUIRK_SUPERIO) {
/* NSC 87560 and maybe others */
temp |= RH_A_NOCP;
temp &= ~(RH_A_POTPGT | RH_A_NPS);
ohci_writel (ohci, temp, &ohci->regs->roothub.a);
val |= RH_A_NOCP;
val &= ~(RH_A_POTPGT | RH_A_NPS);
ohci_writel (ohci, val, &ohci->regs->roothub.a);
} else if ((ohci->flags & OHCI_QUIRK_AMD756) ||
(ohci->flags & OHCI_QUIRK_HUB_POWER)) {
/* hub power always on; required for AMD-756 and some
* Mac platforms. ganged overcurrent reporting, if any.
*/
temp |= RH_A_NPS;
ohci_writel (ohci, temp, &ohci->regs->roothub.a);
val |= RH_A_NPS;
ohci_writel (ohci, val, &ohci->regs->roothub.a);
}
ohci_writel (ohci, RH_HS_LPSC, &ohci->regs->roothub.status);
ohci_writel (ohci, (temp & RH_A_NPS) ? 0 : RH_B_PPCM,
ohci_writel (ohci, (val & RH_A_NPS) ? 0 : RH_B_PPCM,
&ohci->regs->roothub.b);
// flush those writes
(void) ohci_readl (ohci, &ohci->regs->control);
@ -724,7 +724,7 @@ retry:
spin_unlock_irq (&ohci->lock);
// POTPGT delay is bits 24-31, in 2 ms units.
mdelay ((temp >> 23) & 0x1fe);
mdelay ((val >> 23) & 0x1fe);
hcd->state = HC_STATE_RUNNING;
if (quirk_zfmicro(ohci)) {
@ -1105,7 +1105,7 @@ static int __init ohci_hcd_mod_init(void)
set_bit(USB_OHCI_LOADED, &usb_hcds_loaded);
#ifdef DEBUG
ohci_debug_root = debugfs_create_dir("ohci", NULL);
ohci_debug_root = debugfs_create_dir("ohci", usb_debug_root);
if (!ohci_debug_root) {
retval = -ENOENT;
goto error_debug;

View File

@ -372,7 +372,7 @@ static int __devinit ohci_pci_start (struct usb_hcd *hcd)
#ifdef CONFIG_PM
static int ohci_pci_suspend (struct usb_hcd *hcd, pm_message_t message)
static int ohci_pci_suspend(struct usb_hcd *hcd)
{
struct ohci_hcd *ohci = hcd_to_ohci (hcd);
unsigned long flags;
@ -394,10 +394,6 @@ static int ohci_pci_suspend (struct usb_hcd *hcd, pm_message_t message)
ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable);
(void)ohci_readl(ohci, &ohci->regs->intrdisable);
/* make sure snapshot being resumed re-enumerates everything */
if (message.event == PM_EVENT_PRETHAW)
ohci_usb_reset(ohci);
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
bail:
spin_unlock_irqrestore (&ohci->lock, flags);
@ -406,9 +402,14 @@ static int ohci_pci_suspend (struct usb_hcd *hcd, pm_message_t message)
}
static int ohci_pci_resume (struct usb_hcd *hcd)
static int ohci_pci_resume(struct usb_hcd *hcd, bool hibernated)
{
set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
/* Make sure resume from hibernation re-enumerates everything */
if (hibernated)
ohci_usb_reset(hcd_to_ohci(hcd));
ohci_finish_controller_resume(hcd);
return 0;
}
@ -484,12 +485,11 @@ static struct pci_driver ohci_pci_driver = {
.probe = usb_hcd_pci_probe,
.remove = usb_hcd_pci_remove,
#ifdef CONFIG_PM
.suspend = usb_hcd_pci_suspend,
.resume = usb_hcd_pci_resume,
#endif
.shutdown = usb_hcd_pci_shutdown,
};
#ifdef CONFIG_PM_SLEEP
.driver = {
.pm = &usb_hcd_pci_pm_ops
},
#endif
};

View File

@ -15,6 +15,7 @@
#include <linux/delay.h>
#include <linux/acpi.h>
#include "pci-quirks.h"
#include "xhci-ext-caps.h"
#define UHCI_USBLEGSUP 0xc0 /* legacy support */
@ -341,7 +342,127 @@ static void __devinit quirk_usb_disable_ehci(struct pci_dev *pdev)
return;
}
/*
* handshake - spin reading a register until handshake completes
* @ptr: address of hc register to be read
* @mask: bits to look at in result of read
* @done: value of those bits when handshake succeeds
* @wait_usec: timeout in microseconds
* @delay_usec: delay in microseconds to wait between polling
*
* Polls a register every delay_usec microseconds.
* Returns 0 when the mask bits have the value done.
* Returns -ETIMEDOUT if this condition is not true after
* wait_usec microseconds have passed.
*/
static int handshake(void __iomem *ptr, u32 mask, u32 done,
int wait_usec, int delay_usec)
{
u32 result;
do {
result = readl(ptr);
result &= mask;
if (result == done)
return 0;
udelay(delay_usec);
wait_usec -= delay_usec;
} while (wait_usec > 0);
return -ETIMEDOUT;
}
/**
* PCI Quirks for xHCI.
*
* Takes care of the handoff between the Pre-OS (i.e. BIOS) and the OS.
* It signals to the BIOS that the OS wants control of the host controller,
* and then waits 5 seconds for the BIOS to hand over control.
* If we timeout, assume the BIOS is broken and take control anyway.
*/
static void __devinit quirk_usb_handoff_xhci(struct pci_dev *pdev)
{
void __iomem *base;
int ext_cap_offset;
void __iomem *op_reg_base;
u32 val;
int timeout;
if (!mmio_resource_enabled(pdev, 0))
return;
base = ioremap_nocache(pci_resource_start(pdev, 0),
pci_resource_len(pdev, 0));
if (base == NULL)
return;
/*
* Find the Legacy Support Capability register -
* this is optional for xHCI host controllers.
*/
ext_cap_offset = xhci_find_next_cap_offset(base, XHCI_HCC_PARAMS_OFFSET);
do {
if (!ext_cap_offset)
/* We've reached the end of the extended capabilities */
goto hc_init;
val = readl(base + ext_cap_offset);
if (XHCI_EXT_CAPS_ID(val) == XHCI_EXT_CAPS_LEGACY)
break;
ext_cap_offset = xhci_find_next_cap_offset(base, ext_cap_offset);
} while (1);
/* If the BIOS owns the HC, signal that the OS wants it, and wait */
if (val & XHCI_HC_BIOS_OWNED) {
writel(val & XHCI_HC_OS_OWNED, base + ext_cap_offset);
/* Wait for 5 seconds with 10 microsecond polling interval */
timeout = handshake(base + ext_cap_offset, XHCI_HC_BIOS_OWNED,
0, 5000, 10);
/* Assume a buggy BIOS and take HC ownership anyway */
if (timeout) {
dev_warn(&pdev->dev, "xHCI BIOS handoff failed"
" (BIOS bug ?) %08x\n", val);
writel(val & ~XHCI_HC_BIOS_OWNED, base + ext_cap_offset);
}
}
/* Disable any BIOS SMIs */
writel(XHCI_LEGACY_DISABLE_SMI,
base + ext_cap_offset + XHCI_LEGACY_CONTROL_OFFSET);
hc_init:
op_reg_base = base + XHCI_HC_LENGTH(readl(base));
/* Wait for the host controller to be ready before writing any
* operational or runtime registers. Wait 5 seconds and no more.
*/
timeout = handshake(op_reg_base + XHCI_STS_OFFSET, XHCI_STS_CNR, 0,
5000, 10);
/* Assume a buggy HC and start HC initialization anyway */
if (timeout) {
val = readl(op_reg_base + XHCI_STS_OFFSET);
dev_warn(&pdev->dev,
"xHCI HW not ready after 5 sec (HC bug?) "
"status = 0x%x\n", val);
}
/* Send the halt and disable interrupts command */
val = readl(op_reg_base + XHCI_CMD_OFFSET);
val &= ~(XHCI_CMD_RUN | XHCI_IRQS);
writel(val, op_reg_base + XHCI_CMD_OFFSET);
/* Wait for the HC to halt - poll every 125 usec (one microframe). */
timeout = handshake(op_reg_base + XHCI_STS_OFFSET, XHCI_STS_HALT, 1,
XHCI_MAX_HALT_USEC, 125);
if (timeout) {
val = readl(op_reg_base + XHCI_STS_OFFSET);
dev_warn(&pdev->dev,
"xHCI HW did not halt within %d usec "
"status = 0x%x\n", XHCI_MAX_HALT_USEC, val);
}
iounmap(base);
}
static void __devinit quirk_usb_early_handoff(struct pci_dev *pdev)
{
@ -351,5 +472,7 @@ static void __devinit quirk_usb_early_handoff(struct pci_dev *pdev)
quirk_usb_handoff_ohci(pdev);
else if (pdev->class == PCI_CLASS_SERIAL_USB_EHCI)
quirk_usb_disable_ehci(pdev);
else if (pdev->class == PCI_CLASS_SERIAL_USB_XHCI)
quirk_usb_handoff_xhci(pdev);
}
DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_usb_early_handoff);

View File

@ -46,31 +46,10 @@ MODULE_LICENSE("GPL");
MODULE_AUTHOR("Yoshihiro Shimoda");
MODULE_ALIAS("platform:r8a66597_hcd");
#define DRIVER_VERSION "10 Apr 2008"
#define DRIVER_VERSION "2009-05-26"
static const char hcd_name[] = "r8a66597_hcd";
/* module parameters */
#if !defined(CONFIG_SUPERH_ON_CHIP_R8A66597)
static unsigned short clock = XTAL12;
module_param(clock, ushort, 0644);
MODULE_PARM_DESC(clock, "input clock: 48MHz=32768, 24MHz=16384, 12MHz=0 "
"(default=0)");
#endif
static unsigned short vif = LDRV;
module_param(vif, ushort, 0644);
MODULE_PARM_DESC(vif, "input VIF: 3.3V=32768, 1.5V=0(default=32768)");
static unsigned short endian;
module_param(endian, ushort, 0644);
MODULE_PARM_DESC(endian, "data endian: big=256, little=0 (default=0)");
static unsigned short irq_sense = 0xff;
module_param(irq_sense, ushort, 0644);
MODULE_PARM_DESC(irq_sense, "IRQ sense: low level=32, falling edge=0 "
"(default=32)");
static void packet_write(struct r8a66597 *r8a66597, u16 pipenum);
static int r8a66597_get_frame(struct usb_hcd *hcd);
@ -136,7 +115,8 @@ static int r8a66597_clock_enable(struct r8a66597 *r8a66597)
}
} while ((tmp & USBE) != USBE);
r8a66597_bclr(r8a66597, USBE, SYSCFG0);
r8a66597_mdfy(r8a66597, clock, XTAL, SYSCFG0);
r8a66597_mdfy(r8a66597, get_xtal_from_pdata(r8a66597->pdata), XTAL,
SYSCFG0);
i = 0;
r8a66597_bset(r8a66597, XCKE, SYSCFG0);
@ -203,6 +183,9 @@ static void r8a66597_disable_port(struct r8a66597 *r8a66597, int port)
static int enable_controller(struct r8a66597 *r8a66597)
{
int ret, port;
u16 vif = r8a66597->pdata->vif ? LDRV : 0;
u16 irq_sense = r8a66597->irq_sense_low ? INTL : 0;
u16 endian = r8a66597->pdata->endian ? BIGEND : 0;
ret = r8a66597_clock_enable(r8a66597);
if (ret < 0)
@ -2373,7 +2356,7 @@ static int __init_or_module r8a66597_remove(struct platform_device *pdev)
return 0;
}
static int __init r8a66597_probe(struct platform_device *pdev)
static int __devinit r8a66597_probe(struct platform_device *pdev)
{
#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) && defined(CONFIG_HAVE_CLK)
char clk_name[8];
@ -2418,6 +2401,12 @@ static int __init r8a66597_probe(struct platform_device *pdev)
goto clean_up;
}
if (pdev->dev.platform_data == NULL) {
dev_err(&pdev->dev, "no platform data\n");
ret = -ENODEV;
goto clean_up;
}
/* initialize hcd */
hcd = usb_create_hcd(&r8a66597_hc_driver, &pdev->dev, (char *)hcd_name);
if (!hcd) {
@ -2428,6 +2417,8 @@ static int __init r8a66597_probe(struct platform_device *pdev)
r8a66597 = hcd_to_r8a66597(hcd);
memset(r8a66597, 0, sizeof(struct r8a66597));
dev_set_drvdata(&pdev->dev, r8a66597);
r8a66597->pdata = pdev->dev.platform_data;
r8a66597->irq_sense_low = irq_trigger == IRQF_TRIGGER_LOW;
#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) && defined(CONFIG_HAVE_CLK)
snprintf(clk_name, sizeof(clk_name), "usb%d", pdev->id);
@ -2458,29 +2449,6 @@ static int __init r8a66597_probe(struct platform_device *pdev)
hcd->rsrc_start = res->start;
/* irq_sense setting on cmdline takes precedence over resource
* settings, so the introduction of irqflags in IRQ resourse
* won't disturb existing setups */
switch (irq_sense) {
case INTL:
irq_trigger = IRQF_TRIGGER_LOW;
break;
case 0:
irq_trigger = IRQF_TRIGGER_FALLING;
break;
case 0xff:
if (irq_trigger)
irq_sense = (irq_trigger & IRQF_TRIGGER_LOW) ?
INTL : 0;
else {
irq_sense = INTL;
irq_trigger = IRQF_TRIGGER_LOW;
}
break;
default:
dev_err(&pdev->dev, "Unknown irq_sense value.\n");
}
ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | irq_trigger);
if (ret != 0) {
dev_err(&pdev->dev, "Failed to add hcd\n");

View File

@ -30,6 +30,8 @@
#include <linux/clk.h>
#endif
#include <linux/usb/r8a66597.h>
#define SYSCFG0 0x00
#define SYSCFG1 0x02
#define SYSSTS0 0x04
@ -488,6 +490,7 @@ struct r8a66597 {
#if defined(CONFIG_SUPERH_ON_CHIP_R8A66597) && defined(CONFIG_HAVE_CLK)
struct clk *clk;
#endif
struct r8a66597_platdata *pdata;
struct r8a66597_device device0;
struct r8a66597_root_hub root_hub[R8A66597_MAX_ROOT_HUB];
struct list_head pipe_queue[R8A66597_MAX_NUM_PIPE];
@ -506,6 +509,7 @@ struct r8a66597 {
unsigned long child_connect_map[4];
unsigned bus_suspended:1;
unsigned irq_sense_low:1;
};
static inline struct r8a66597 *hcd_to_r8a66597(struct usb_hcd *hcd)
@ -660,10 +664,36 @@ static inline void r8a66597_port_power(struct r8a66597 *r8a66597, int port,
{
unsigned long dvstctr_reg = get_dvstctr_reg(port);
if (power)
r8a66597_bset(r8a66597, VBOUT, dvstctr_reg);
else
r8a66597_bclr(r8a66597, VBOUT, dvstctr_reg);
if (r8a66597->pdata->port_power) {
r8a66597->pdata->port_power(port, power);
} else {
if (power)
r8a66597_bset(r8a66597, VBOUT, dvstctr_reg);
else
r8a66597_bclr(r8a66597, VBOUT, dvstctr_reg);
}
}
static inline u16 get_xtal_from_pdata(struct r8a66597_platdata *pdata)
{
u16 clock = 0;
switch (pdata->xtal) {
case R8A66597_PLATDATA_XTAL_12MHZ:
clock = XTAL12;
break;
case R8A66597_PLATDATA_XTAL_24MHZ:
clock = XTAL24;
break;
case R8A66597_PLATDATA_XTAL_48MHZ:
clock = XTAL48;
break;
default:
printk(KERN_ERR "r8a66597: platdata clock is wrong.\n");
break;
}
return clock;
}
#define get_pipectr_addr(pipenum) (PIPE1CTR + (pipenum - 1) * 2)

View File

@ -769,7 +769,7 @@ static int uhci_rh_resume(struct usb_hcd *hcd)
return rc;
}
static int uhci_pci_suspend(struct usb_hcd *hcd, pm_message_t message)
static int uhci_pci_suspend(struct usb_hcd *hcd)
{
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
int rc = 0;
@ -795,10 +795,6 @@ static int uhci_pci_suspend(struct usb_hcd *hcd, pm_message_t message)
/* FIXME: Enable non-PME# remote wakeup? */
/* make sure snapshot being resumed re-enumerates everything */
if (message.event == PM_EVENT_PRETHAW)
uhci_hc_died(uhci);
done_okay:
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
done:
@ -806,7 +802,7 @@ done:
return rc;
}
static int uhci_pci_resume(struct usb_hcd *hcd)
static int uhci_pci_resume(struct usb_hcd *hcd, bool hibernated)
{
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
@ -820,6 +816,10 @@ static int uhci_pci_resume(struct usb_hcd *hcd)
spin_lock_irq(&uhci->lock);
/* Make sure resume from hibernation re-enumerates everything */
if (hibernated)
uhci_hc_died(uhci);
/* FIXME: Disable non-PME# remote wakeup? */
/* The firmware or a boot kernel may have changed the controller
@ -940,10 +940,11 @@ static struct pci_driver uhci_pci_driver = {
.remove = usb_hcd_pci_remove,
.shutdown = uhci_shutdown,
#ifdef CONFIG_PM
.suspend = usb_hcd_pci_suspend,
.resume = usb_hcd_pci_resume,
#endif /* PM */
#ifdef CONFIG_PM_SLEEP
.driver = {
.pm = &usb_hcd_pci_pm_ops
},
#endif
};
static int __init uhci_hcd_init(void)
@ -961,7 +962,7 @@ static int __init uhci_hcd_init(void)
errbuf = kmalloc(ERRBUF_LEN, GFP_KERNEL);
if (!errbuf)
goto errbuf_failed;
uhci_debugfs_root = debugfs_create_dir("uhci", NULL);
uhci_debugfs_root = debugfs_create_dir("uhci", usb_debug_root);
if (!uhci_debugfs_root)
goto debug_failed;
}

View File

@ -260,7 +260,7 @@ static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci,
INIT_LIST_HEAD(&qh->node);
if (udev) { /* Normal QH */
qh->type = hep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
qh->type = usb_endpoint_type(&hep->desc);
if (qh->type != USB_ENDPOINT_XFER_ISOC) {
qh->dummy_td = uhci_alloc_td(uhci);
if (!qh->dummy_td) {

View File

@ -0,0 +1,485 @@
/*
* xHCI host controller driver
*
* Copyright (C) 2008 Intel Corp.
*
* Author: Sarah Sharp
* Some code borrowed from the Linux EHCI driver.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* 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 "xhci.h"
#define XHCI_INIT_VALUE 0x0
/* Add verbose debugging later, just print everything for now */
void xhci_dbg_regs(struct xhci_hcd *xhci)
{
u32 temp;
xhci_dbg(xhci, "// xHCI capability registers at %p:\n",
xhci->cap_regs);
temp = xhci_readl(xhci, &xhci->cap_regs->hc_capbase);
xhci_dbg(xhci, "// @%p = 0x%x (CAPLENGTH AND HCIVERSION)\n",
&xhci->cap_regs->hc_capbase, temp);
xhci_dbg(xhci, "// CAPLENGTH: 0x%x\n",
(unsigned int) HC_LENGTH(temp));
#if 0
xhci_dbg(xhci, "// HCIVERSION: 0x%x\n",
(unsigned int) HC_VERSION(temp));
#endif
xhci_dbg(xhci, "// xHCI operational registers at %p:\n", xhci->op_regs);
temp = xhci_readl(xhci, &xhci->cap_regs->run_regs_off);
xhci_dbg(xhci, "// @%p = 0x%x RTSOFF\n",
&xhci->cap_regs->run_regs_off,
(unsigned int) temp & RTSOFF_MASK);
xhci_dbg(xhci, "// xHCI runtime registers at %p:\n", xhci->run_regs);
temp = xhci_readl(xhci, &xhci->cap_regs->db_off);
xhci_dbg(xhci, "// @%p = 0x%x DBOFF\n", &xhci->cap_regs->db_off, temp);
xhci_dbg(xhci, "// Doorbell array at %p:\n", xhci->dba);
}
static void xhci_print_cap_regs(struct xhci_hcd *xhci)
{
u32 temp;
xhci_dbg(xhci, "xHCI capability registers at %p:\n", xhci->cap_regs);
temp = xhci_readl(xhci, &xhci->cap_regs->hc_capbase);
xhci_dbg(xhci, "CAPLENGTH AND HCIVERSION 0x%x:\n",
(unsigned int) temp);
xhci_dbg(xhci, "CAPLENGTH: 0x%x\n",
(unsigned int) HC_LENGTH(temp));
xhci_dbg(xhci, "HCIVERSION: 0x%x\n",
(unsigned int) HC_VERSION(temp));
temp = xhci_readl(xhci, &xhci->cap_regs->hcs_params1);
xhci_dbg(xhci, "HCSPARAMS 1: 0x%x\n",
(unsigned int) temp);
xhci_dbg(xhci, " Max device slots: %u\n",
(unsigned int) HCS_MAX_SLOTS(temp));
xhci_dbg(xhci, " Max interrupters: %u\n",
(unsigned int) HCS_MAX_INTRS(temp));
xhci_dbg(xhci, " Max ports: %u\n",
(unsigned int) HCS_MAX_PORTS(temp));
temp = xhci_readl(xhci, &xhci->cap_regs->hcs_params2);
xhci_dbg(xhci, "HCSPARAMS 2: 0x%x\n",
(unsigned int) temp);
xhci_dbg(xhci, " Isoc scheduling threshold: %u\n",
(unsigned int) HCS_IST(temp));
xhci_dbg(xhci, " Maximum allowed segments in event ring: %u\n",
(unsigned int) HCS_ERST_MAX(temp));
temp = xhci_readl(xhci, &xhci->cap_regs->hcs_params3);
xhci_dbg(xhci, "HCSPARAMS 3 0x%x:\n",
(unsigned int) temp);
xhci_dbg(xhci, " Worst case U1 device exit latency: %u\n",
(unsigned int) HCS_U1_LATENCY(temp));
xhci_dbg(xhci, " Worst case U2 device exit latency: %u\n",
(unsigned int) HCS_U2_LATENCY(temp));
temp = xhci_readl(xhci, &xhci->cap_regs->hcc_params);
xhci_dbg(xhci, "HCC PARAMS 0x%x:\n", (unsigned int) temp);
xhci_dbg(xhci, " HC generates %s bit addresses\n",
HCC_64BIT_ADDR(temp) ? "64" : "32");
/* FIXME */
xhci_dbg(xhci, " FIXME: more HCCPARAMS debugging\n");
temp = xhci_readl(xhci, &xhci->cap_regs->run_regs_off);
xhci_dbg(xhci, "RTSOFF 0x%x:\n", temp & RTSOFF_MASK);
}
static void xhci_print_command_reg(struct xhci_hcd *xhci)
{
u32 temp;
temp = xhci_readl(xhci, &xhci->op_regs->command);
xhci_dbg(xhci, "USBCMD 0x%x:\n", temp);
xhci_dbg(xhci, " HC is %s\n",
(temp & CMD_RUN) ? "running" : "being stopped");
xhci_dbg(xhci, " HC has %sfinished hard reset\n",
(temp & CMD_RESET) ? "not " : "");
xhci_dbg(xhci, " Event Interrupts %s\n",
(temp & CMD_EIE) ? "enabled " : "disabled");
xhci_dbg(xhci, " Host System Error Interrupts %s\n",
(temp & CMD_EIE) ? "enabled " : "disabled");
xhci_dbg(xhci, " HC has %sfinished light reset\n",
(temp & CMD_LRESET) ? "not " : "");
}
static void xhci_print_status(struct xhci_hcd *xhci)
{
u32 temp;
temp = xhci_readl(xhci, &xhci->op_regs->status);
xhci_dbg(xhci, "USBSTS 0x%x:\n", temp);
xhci_dbg(xhci, " Event ring is %sempty\n",
(temp & STS_EINT) ? "not " : "");
xhci_dbg(xhci, " %sHost System Error\n",
(temp & STS_FATAL) ? "WARNING: " : "No ");
xhci_dbg(xhci, " HC is %s\n",
(temp & STS_HALT) ? "halted" : "running");
}
static void xhci_print_op_regs(struct xhci_hcd *xhci)
{
xhci_dbg(xhci, "xHCI operational registers at %p:\n", xhci->op_regs);
xhci_print_command_reg(xhci);
xhci_print_status(xhci);
}
static void xhci_print_ports(struct xhci_hcd *xhci)
{
u32 __iomem *addr;
int i, j;
int ports;
char *names[NUM_PORT_REGS] = {
"status",
"power",
"link",
"reserved",
};
ports = HCS_MAX_PORTS(xhci->hcs_params1);
addr = &xhci->op_regs->port_status_base;
for (i = 0; i < ports; i++) {
for (j = 0; j < NUM_PORT_REGS; ++j) {
xhci_dbg(xhci, "%p port %s reg = 0x%x\n",
addr, names[j],
(unsigned int) xhci_readl(xhci, addr));
addr++;
}
}
}
void xhci_print_ir_set(struct xhci_hcd *xhci, struct xhci_intr_reg *ir_set, int set_num)
{
void *addr;
u32 temp;
addr = &ir_set->irq_pending;
temp = xhci_readl(xhci, addr);
if (temp == XHCI_INIT_VALUE)
return;
xhci_dbg(xhci, " %p: ir_set[%i]\n", ir_set, set_num);
xhci_dbg(xhci, " %p: ir_set.pending = 0x%x\n", addr,
(unsigned int)temp);
addr = &ir_set->irq_control;
temp = xhci_readl(xhci, addr);
xhci_dbg(xhci, " %p: ir_set.control = 0x%x\n", addr,
(unsigned int)temp);
addr = &ir_set->erst_size;
temp = xhci_readl(xhci, addr);
xhci_dbg(xhci, " %p: ir_set.erst_size = 0x%x\n", addr,
(unsigned int)temp);
addr = &ir_set->rsvd;
temp = xhci_readl(xhci, addr);
if (temp != XHCI_INIT_VALUE)
xhci_dbg(xhci, " WARN: %p: ir_set.rsvd = 0x%x\n",
addr, (unsigned int)temp);
addr = &ir_set->erst_base[0];
temp = xhci_readl(xhci, addr);
xhci_dbg(xhci, " %p: ir_set.erst_base[0] = 0x%x\n",
addr, (unsigned int) temp);
addr = &ir_set->erst_base[1];
temp = xhci_readl(xhci, addr);
xhci_dbg(xhci, " %p: ir_set.erst_base[1] = 0x%x\n",
addr, (unsigned int) temp);
addr = &ir_set->erst_dequeue[0];
temp = xhci_readl(xhci, addr);
xhci_dbg(xhci, " %p: ir_set.erst_dequeue[0] = 0x%x\n",
addr, (unsigned int) temp);
addr = &ir_set->erst_dequeue[1];
temp = xhci_readl(xhci, addr);
xhci_dbg(xhci, " %p: ir_set.erst_dequeue[1] = 0x%x\n",
addr, (unsigned int) temp);
}
void xhci_print_run_regs(struct xhci_hcd *xhci)
{
u32 temp;
int i;
xhci_dbg(xhci, "xHCI runtime registers at %p:\n", xhci->run_regs);
temp = xhci_readl(xhci, &xhci->run_regs->microframe_index);
xhci_dbg(xhci, " %p: Microframe index = 0x%x\n",
&xhci->run_regs->microframe_index,
(unsigned int) temp);
for (i = 0; i < 7; ++i) {
temp = xhci_readl(xhci, &xhci->run_regs->rsvd[i]);
if (temp != XHCI_INIT_VALUE)
xhci_dbg(xhci, " WARN: %p: Rsvd[%i] = 0x%x\n",
&xhci->run_regs->rsvd[i],
i, (unsigned int) temp);
}
}
void xhci_print_registers(struct xhci_hcd *xhci)
{
xhci_print_cap_regs(xhci);
xhci_print_op_regs(xhci);
xhci_print_ports(xhci);
}
void xhci_print_trb_offsets(struct xhci_hcd *xhci, union xhci_trb *trb)
{
int i;
for (i = 0; i < 4; ++i)
xhci_dbg(xhci, "Offset 0x%x = 0x%x\n",
i*4, trb->generic.field[i]);
}
/**
* Debug a transfer request block (TRB).
*/
void xhci_debug_trb(struct xhci_hcd *xhci, union xhci_trb *trb)
{
u64 address;
u32 type = xhci_readl(xhci, &trb->link.control) & TRB_TYPE_BITMASK;
switch (type) {
case TRB_TYPE(TRB_LINK):
xhci_dbg(xhci, "Link TRB:\n");
xhci_print_trb_offsets(xhci, trb);
address = trb->link.segment_ptr[0] +
(((u64) trb->link.segment_ptr[1]) << 32);
xhci_dbg(xhci, "Next ring segment DMA address = 0x%llx\n", address);
xhci_dbg(xhci, "Interrupter target = 0x%x\n",
GET_INTR_TARGET(trb->link.intr_target));
xhci_dbg(xhci, "Cycle bit = %u\n",
(unsigned int) (trb->link.control & TRB_CYCLE));
xhci_dbg(xhci, "Toggle cycle bit = %u\n",
(unsigned int) (trb->link.control & LINK_TOGGLE));
xhci_dbg(xhci, "No Snoop bit = %u\n",
(unsigned int) (trb->link.control & TRB_NO_SNOOP));
break;
case TRB_TYPE(TRB_TRANSFER):
address = trb->trans_event.buffer[0] +
(((u64) trb->trans_event.buffer[1]) << 32);
/*
* FIXME: look at flags to figure out if it's an address or if
* the data is directly in the buffer field.
*/
xhci_dbg(xhci, "DMA address or buffer contents= %llu\n", address);
break;
case TRB_TYPE(TRB_COMPLETION):
address = trb->event_cmd.cmd_trb[0] +
(((u64) trb->event_cmd.cmd_trb[1]) << 32);
xhci_dbg(xhci, "Command TRB pointer = %llu\n", address);
xhci_dbg(xhci, "Completion status = %u\n",
(unsigned int) GET_COMP_CODE(trb->event_cmd.status));
xhci_dbg(xhci, "Flags = 0x%x\n", (unsigned int) trb->event_cmd.flags);
break;
default:
xhci_dbg(xhci, "Unknown TRB with TRB type ID %u\n",
(unsigned int) type>>10);
xhci_print_trb_offsets(xhci, trb);
break;
}
}
/**
* Debug a segment with an xHCI ring.
*
* @return The Link TRB of the segment, or NULL if there is no Link TRB
* (which is a bug, since all segments must have a Link TRB).
*
* Prints out all TRBs in the segment, even those after the Link TRB.
*
* XXX: should we print out TRBs that the HC owns? As long as we don't
* write, that should be fine... We shouldn't expect that the memory pointed to
* by the TRB is valid at all. Do we care about ones the HC owns? Probably,
* for HC debugging.
*/
void xhci_debug_segment(struct xhci_hcd *xhci, struct xhci_segment *seg)
{
int i;
u32 addr = (u32) seg->dma;
union xhci_trb *trb = seg->trbs;
for (i = 0; i < TRBS_PER_SEGMENT; ++i) {
trb = &seg->trbs[i];
xhci_dbg(xhci, "@%08x %08x %08x %08x %08x\n", addr,
(unsigned int) trb->link.segment_ptr[0],
(unsigned int) trb->link.segment_ptr[1],
(unsigned int) trb->link.intr_target,
(unsigned int) trb->link.control);
addr += sizeof(*trb);
}
}
void xhci_dbg_ring_ptrs(struct xhci_hcd *xhci, struct xhci_ring *ring)
{
xhci_dbg(xhci, "Ring deq = %p (virt), 0x%llx (dma)\n",
ring->dequeue,
(unsigned long long)xhci_trb_virt_to_dma(ring->deq_seg,
ring->dequeue));
xhci_dbg(xhci, "Ring deq updated %u times\n",
ring->deq_updates);
xhci_dbg(xhci, "Ring enq = %p (virt), 0x%llx (dma)\n",
ring->enqueue,
(unsigned long long)xhci_trb_virt_to_dma(ring->enq_seg,
ring->enqueue));
xhci_dbg(xhci, "Ring enq updated %u times\n",
ring->enq_updates);
}
/**
* Debugging for an xHCI ring, which is a queue broken into multiple segments.
*
* Print out each segment in the ring. Check that the DMA address in
* each link segment actually matches the segment's stored DMA address.
* Check that the link end bit is only set at the end of the ring.
* Check that the dequeue and enqueue pointers point to real data in this ring
* (not some other ring).
*/
void xhci_debug_ring(struct xhci_hcd *xhci, struct xhci_ring *ring)
{
/* FIXME: Throw an error if any segment doesn't have a Link TRB */
struct xhci_segment *seg;
struct xhci_segment *first_seg = ring->first_seg;
xhci_debug_segment(xhci, first_seg);
if (!ring->enq_updates && !ring->deq_updates) {
xhci_dbg(xhci, " Ring has not been updated\n");
return;
}
for (seg = first_seg->next; seg != first_seg; seg = seg->next)
xhci_debug_segment(xhci, seg);
}
void xhci_dbg_erst(struct xhci_hcd *xhci, struct xhci_erst *erst)
{
u32 addr = (u32) erst->erst_dma_addr;
int i;
struct xhci_erst_entry *entry;
for (i = 0; i < erst->num_entries; ++i) {
entry = &erst->entries[i];
xhci_dbg(xhci, "@%08x %08x %08x %08x %08x\n",
(unsigned int) addr,
(unsigned int) entry->seg_addr[0],
(unsigned int) entry->seg_addr[1],
(unsigned int) entry->seg_size,
(unsigned int) entry->rsvd);
addr += sizeof(*entry);
}
}
void xhci_dbg_cmd_ptrs(struct xhci_hcd *xhci)
{
u32 val;
val = xhci_readl(xhci, &xhci->op_regs->cmd_ring[0]);
xhci_dbg(xhci, "// xHC command ring deq ptr low bits + flags = 0x%x\n", val);
val = xhci_readl(xhci, &xhci->op_regs->cmd_ring[1]);
xhci_dbg(xhci, "// xHC command ring deq ptr high bits = 0x%x\n", val);
}
void xhci_dbg_ctx(struct xhci_hcd *xhci, struct xhci_device_control *ctx, dma_addr_t dma, unsigned int last_ep)
{
int i, j;
int last_ep_ctx = 31;
/* Fields are 32 bits wide, DMA addresses are in bytes */
int field_size = 32 / 8;
xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - drop flags\n",
&ctx->drop_flags, (unsigned long long)dma,
ctx->drop_flags);
dma += field_size;
xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - add flags\n",
&ctx->add_flags, (unsigned long long)dma,
ctx->add_flags);
dma += field_size;
for (i = 0; i > 6; ++i) {
xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - rsvd[%d]\n",
&ctx->rsvd[i], (unsigned long long)dma,
ctx->rsvd[i], i);
dma += field_size;
}
xhci_dbg(xhci, "Slot Context:\n");
xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - dev_info\n",
&ctx->slot.dev_info,
(unsigned long long)dma, ctx->slot.dev_info);
dma += field_size;
xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - dev_info2\n",
&ctx->slot.dev_info2,
(unsigned long long)dma, ctx->slot.dev_info2);
dma += field_size;
xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - tt_info\n",
&ctx->slot.tt_info,
(unsigned long long)dma, ctx->slot.tt_info);
dma += field_size;
xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - dev_state\n",
&ctx->slot.dev_state,
(unsigned long long)dma, ctx->slot.dev_state);
dma += field_size;
for (i = 0; i > 4; ++i) {
xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - rsvd[%d]\n",
&ctx->slot.reserved[i], (unsigned long long)dma,
ctx->slot.reserved[i], i);
dma += field_size;
}
if (last_ep < 31)
last_ep_ctx = last_ep + 1;
for (i = 0; i < last_ep_ctx; ++i) {
xhci_dbg(xhci, "Endpoint %02d Context:\n", i);
xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - ep_info\n",
&ctx->ep[i].ep_info,
(unsigned long long)dma, ctx->ep[i].ep_info);
dma += field_size;
xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - ep_info2\n",
&ctx->ep[i].ep_info2,
(unsigned long long)dma, ctx->ep[i].ep_info2);
dma += field_size;
xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - deq[0]\n",
&ctx->ep[i].deq[0],
(unsigned long long)dma, ctx->ep[i].deq[0]);
dma += field_size;
xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - deq[1]\n",
&ctx->ep[i].deq[1],
(unsigned long long)dma, ctx->ep[i].deq[1]);
dma += field_size;
xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - tx_info\n",
&ctx->ep[i].tx_info,
(unsigned long long)dma, ctx->ep[i].tx_info);
dma += field_size;
for (j = 0; j < 3; ++j) {
xhci_dbg(xhci, "@%p (virt) @%08llx (dma) %#08x - rsvd[%d]\n",
&ctx->ep[i].reserved[j],
(unsigned long long)dma,
ctx->ep[i].reserved[j], j);
dma += field_size;
}
}
}

View File

@ -0,0 +1,145 @@
/*
* xHCI host controller driver
*
* Copyright (C) 2008 Intel Corp.
*
* Author: Sarah Sharp
* Some code borrowed from the Linux EHCI driver.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* 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.
*/
/* Up to 16 microframes to halt an HC - one microframe is 125 microsectonds */
#define XHCI_MAX_HALT_USEC (16*125)
/* HC not running - set to 1 when run/stop bit is cleared. */
#define XHCI_STS_HALT (1<<0)
/* HCCPARAMS offset from PCI base address */
#define XHCI_HCC_PARAMS_OFFSET 0x10
/* HCCPARAMS contains the first extended capability pointer */
#define XHCI_HCC_EXT_CAPS(p) (((p)>>16)&0xffff)
/* Command and Status registers offset from the Operational Registers address */
#define XHCI_CMD_OFFSET 0x00
#define XHCI_STS_OFFSET 0x04
#define XHCI_MAX_EXT_CAPS 50
/* Capability Register */
/* bits 7:0 - how long is the Capabilities register */
#define XHCI_HC_LENGTH(p) (((p)>>00)&0x00ff)
/* Extended capability register fields */
#define XHCI_EXT_CAPS_ID(p) (((p)>>0)&0xff)
#define XHCI_EXT_CAPS_NEXT(p) (((p)>>8)&0xff)
#define XHCI_EXT_CAPS_VAL(p) ((p)>>16)
/* Extended capability IDs - ID 0 reserved */
#define XHCI_EXT_CAPS_LEGACY 1
#define XHCI_EXT_CAPS_PROTOCOL 2
#define XHCI_EXT_CAPS_PM 3
#define XHCI_EXT_CAPS_VIRT 4
#define XHCI_EXT_CAPS_ROUTE 5
/* IDs 6-9 reserved */
#define XHCI_EXT_CAPS_DEBUG 10
/* USB Legacy Support Capability - section 7.1.1 */
#define XHCI_HC_BIOS_OWNED (1 << 16)
#define XHCI_HC_OS_OWNED (1 << 24)
/* USB Legacy Support Capability - section 7.1.1 */
/* Add this offset, plus the value of xECP in HCCPARAMS to the base address */
#define XHCI_LEGACY_SUPPORT_OFFSET (0x00)
/* USB Legacy Support Control and Status Register - section 7.1.2 */
/* Add this offset, plus the value of xECP in HCCPARAMS to the base address */
#define XHCI_LEGACY_CONTROL_OFFSET (0x04)
/* bits 1:2, 5:12, and 17:19 need to be preserved; bits 21:28 should be zero */
#define XHCI_LEGACY_DISABLE_SMI ((0x3 << 1) + (0xff << 5) + (0x7 << 17))
/* command register values to disable interrupts and halt the HC */
/* start/stop HC execution - do not write unless HC is halted*/
#define XHCI_CMD_RUN (1 << 0)
/* Event Interrupt Enable - get irq when EINT bit is set in USBSTS register */
#define XHCI_CMD_EIE (1 << 2)
/* Host System Error Interrupt Enable - get irq when HSEIE bit set in USBSTS */
#define XHCI_CMD_HSEIE (1 << 3)
/* Enable Wrap Event - '1' means xHC generates an event when MFINDEX wraps. */
#define XHCI_CMD_EWE (1 << 10)
#define XHCI_IRQS (XHCI_CMD_EIE | XHCI_CMD_HSEIE | XHCI_CMD_EWE)
/* true: Controller Not Ready to accept doorbell or op reg writes after reset */
#define XHCI_STS_CNR (1 << 11)
#include <linux/io.h>
/**
* Return the next extended capability pointer register.
*
* @base PCI register base address.
*
* @ext_offset Offset of the 32-bit register that contains the extended
* capabilites pointer. If searching for the first extended capability, pass
* in XHCI_HCC_PARAMS_OFFSET. If searching for the next extended capability,
* pass in the offset of the current extended capability register.
*
* Returns 0 if there is no next extended capability register or returns the register offset
* from the PCI registers base address.
*/
static inline int xhci_find_next_cap_offset(void __iomem *base, int ext_offset)
{
u32 next;
next = readl(base + ext_offset);
if (ext_offset == XHCI_HCC_PARAMS_OFFSET)
/* Find the first extended capability */
next = XHCI_HCC_EXT_CAPS(next);
else
/* Find the next extended capability */
next = XHCI_EXT_CAPS_NEXT(next);
if (!next)
return 0;
/*
* Address calculation from offset of extended capabilities
* (or HCCPARAMS) register - see section 5.3.6 and section 7.
*/
return ext_offset + (next << 2);
}
/**
* Find the offset of the extended capabilities with capability ID id.
*
* @base PCI MMIO registers base address.
* @ext_offset Offset from base of the first extended capability to look at,
* or the address of HCCPARAMS.
* @id Extended capability ID to search for.
*
* This uses an arbitrary limit of XHCI_MAX_EXT_CAPS extended capabilities
* to make sure that the list doesn't contain a loop.
*/
static inline int xhci_find_ext_cap_by_id(void __iomem *base, int ext_offset, int id)
{
u32 val;
int limit = XHCI_MAX_EXT_CAPS;
while (ext_offset && limit > 0) {
val = readl(base + ext_offset);
if (XHCI_EXT_CAPS_ID(val) == id)
break;
ext_offset = xhci_find_next_cap_offset(base, ext_offset);
limit--;
}
if (limit > 0)
return ext_offset;
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,308 @@
/*
* xHCI host controller driver
*
* Copyright (C) 2008 Intel Corp.
*
* Author: Sarah Sharp
* Some code borrowed from the Linux EHCI driver.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* 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 <asm/unaligned.h>
#include "xhci.h"
static void xhci_hub_descriptor(struct xhci_hcd *xhci,
struct usb_hub_descriptor *desc)
{
int ports;
u16 temp;
ports = HCS_MAX_PORTS(xhci->hcs_params1);
/* USB 3.0 hubs have a different descriptor, but we fake this for now */
desc->bDescriptorType = 0x29;
desc->bPwrOn2PwrGood = 10; /* xhci section 5.4.9 says 20ms max */
desc->bHubContrCurrent = 0;
desc->bNbrPorts = ports;
temp = 1 + (ports / 8);
desc->bDescLength = 7 + 2 * temp;
/* Why does core/hcd.h define bitmap? It's just confusing. */
memset(&desc->DeviceRemovable[0], 0, temp);
memset(&desc->DeviceRemovable[temp], 0xff, temp);
/* Ugh, these should be #defines, FIXME */
/* Using table 11-13 in USB 2.0 spec. */
temp = 0;
/* Bits 1:0 - support port power switching, or power always on */
if (HCC_PPC(xhci->hcc_params))
temp |= 0x0001;
else
temp |= 0x0002;
/* Bit 2 - root hubs are not part of a compound device */
/* Bits 4:3 - individual port over current protection */
temp |= 0x0008;
/* Bits 6:5 - no TTs in root ports */
/* Bit 7 - no port indicators */
desc->wHubCharacteristics = (__force __u16) cpu_to_le16(temp);
}
static unsigned int xhci_port_speed(unsigned int port_status)
{
if (DEV_LOWSPEED(port_status))
return 1 << USB_PORT_FEAT_LOWSPEED;
if (DEV_HIGHSPEED(port_status))
return 1 << USB_PORT_FEAT_HIGHSPEED;
if (DEV_SUPERSPEED(port_status))
return 1 << USB_PORT_FEAT_SUPERSPEED;
/*
* FIXME: Yes, we should check for full speed, but the core uses that as
* a default in portspeed() in usb/core/hub.c (which is the only place
* USB_PORT_FEAT_*SPEED is used).
*/
return 0;
}
/*
* These bits are Read Only (RO) and should be saved and written to the
* registers: 0, 3, 10:13, 30
* connect status, over-current status, port speed, and device removable.
* connect status and port speed are also sticky - meaning they're in
* the AUX well and they aren't changed by a hot, warm, or cold reset.
*/
#define XHCI_PORT_RO ((1<<0) | (1<<3) | (0xf<<10) | (1<<30))
/*
* These bits are RW; writing a 0 clears the bit, writing a 1 sets the bit:
* bits 5:8, 9, 14:15, 25:27
* link state, port power, port indicator state, "wake on" enable state
*/
#define XHCI_PORT_RWS ((0xf<<5) | (1<<9) | (0x3<<14) | (0x7<<25))
/*
* These bits are RW; writing a 1 sets the bit, writing a 0 has no effect:
* bit 4 (port reset)
*/
#define XHCI_PORT_RW1S ((1<<4))
/*
* These bits are RW; writing a 1 clears the bit, writing a 0 has no effect:
* bits 1, 17, 18, 19, 20, 21, 22, 23
* port enable/disable, and
* change bits: connect, PED, warm port reset changed (reserved zero for USB 2.0 ports),
* over-current, reset, link state, and L1 change
*/
#define XHCI_PORT_RW1CS ((1<<1) | (0x7f<<17))
/*
* Bit 16 is RW, and writing a '1' to it causes the link state control to be
* latched in
*/
#define XHCI_PORT_RW ((1<<16))
/*
* These bits are Reserved Zero (RsvdZ) and zero should be written to them:
* bits 2, 24, 28:31
*/
#define XHCI_PORT_RZ ((1<<2) | (1<<24) | (0xf<<28))
/*
* Given a port state, this function returns a value that would result in the
* port being in the same state, if the value was written to the port status
* control register.
* Save Read Only (RO) bits and save read/write bits where
* writing a 0 clears the bit and writing a 1 sets the bit (RWS).
* For all other types (RW1S, RW1CS, RW, and RZ), writing a '0' has no effect.
*/
static u32 xhci_port_state_to_neutral(u32 state)
{
/* Save read-only status and port state */
return (state & XHCI_PORT_RO) | (state & XHCI_PORT_RWS);
}
int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
u16 wIndex, char *buf, u16 wLength)
{
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
int ports;
unsigned long flags;
u32 temp, status;
int retval = 0;
u32 __iomem *addr;
char *port_change_bit;
ports = HCS_MAX_PORTS(xhci->hcs_params1);
spin_lock_irqsave(&xhci->lock, flags);
switch (typeReq) {
case GetHubStatus:
/* No power source, over-current reported per port */
memset(buf, 0, 4);
break;
case GetHubDescriptor:
xhci_hub_descriptor(xhci, (struct usb_hub_descriptor *) buf);
break;
case GetPortStatus:
if (!wIndex || wIndex > ports)
goto error;
wIndex--;
status = 0;
addr = &xhci->op_regs->port_status_base + NUM_PORT_REGS*(wIndex & 0xff);
temp = xhci_readl(xhci, addr);
xhci_dbg(xhci, "get port status, actual port %d status = 0x%x\n", wIndex, temp);
/* wPortChange bits */
if (temp & PORT_CSC)
status |= 1 << USB_PORT_FEAT_C_CONNECTION;
if (temp & PORT_PEC)
status |= 1 << USB_PORT_FEAT_C_ENABLE;
if ((temp & PORT_OCC))
status |= 1 << USB_PORT_FEAT_C_OVER_CURRENT;
/*
* FIXME ignoring suspend, reset, and USB 2.1/3.0 specific
* changes
*/
if (temp & PORT_CONNECT) {
status |= 1 << USB_PORT_FEAT_CONNECTION;
status |= xhci_port_speed(temp);
}
if (temp & PORT_PE)
status |= 1 << USB_PORT_FEAT_ENABLE;
if (temp & PORT_OC)
status |= 1 << USB_PORT_FEAT_OVER_CURRENT;
if (temp & PORT_RESET)
status |= 1 << USB_PORT_FEAT_RESET;
if (temp & PORT_POWER)
status |= 1 << USB_PORT_FEAT_POWER;
xhci_dbg(xhci, "Get port status returned 0x%x\n", status);
put_unaligned(cpu_to_le32(status), (__le32 *) buf);
break;
case SetPortFeature:
wIndex &= 0xff;
if (!wIndex || wIndex > ports)
goto error;
wIndex--;
addr = &xhci->op_regs->port_status_base + NUM_PORT_REGS*(wIndex & 0xff);
temp = xhci_readl(xhci, addr);
temp = xhci_port_state_to_neutral(temp);
switch (wValue) {
case USB_PORT_FEAT_POWER:
/*
* Turn on ports, even if there isn't per-port switching.
* HC will report connect events even before this is set.
* However, khubd will ignore the roothub events until
* the roothub is registered.
*/
xhci_writel(xhci, temp | PORT_POWER, addr);
temp = xhci_readl(xhci, addr);
xhci_dbg(xhci, "set port power, actual port %d status = 0x%x\n", wIndex, temp);
break;
case USB_PORT_FEAT_RESET:
temp = (temp | PORT_RESET);
xhci_writel(xhci, temp, addr);
temp = xhci_readl(xhci, addr);
xhci_dbg(xhci, "set port reset, actual port %d status = 0x%x\n", wIndex, temp);
break;
default:
goto error;
}
temp = xhci_readl(xhci, addr); /* unblock any posted writes */
break;
case ClearPortFeature:
if (!wIndex || wIndex > ports)
goto error;
wIndex--;
addr = &xhci->op_regs->port_status_base +
NUM_PORT_REGS*(wIndex & 0xff);
temp = xhci_readl(xhci, addr);
temp = xhci_port_state_to_neutral(temp);
switch (wValue) {
case USB_PORT_FEAT_C_RESET:
status = PORT_RC;
port_change_bit = "reset";
break;
case USB_PORT_FEAT_C_CONNECTION:
status = PORT_CSC;
port_change_bit = "connect";
break;
case USB_PORT_FEAT_C_OVER_CURRENT:
status = PORT_OCC;
port_change_bit = "over-current";
break;
default:
goto error;
}
/* Change bits are all write 1 to clear */
xhci_writel(xhci, temp | status, addr);
temp = xhci_readl(xhci, addr);
xhci_dbg(xhci, "clear port %s change, actual port %d status = 0x%x\n",
port_change_bit, wIndex, temp);
temp = xhci_readl(xhci, addr); /* unblock any posted writes */
break;
default:
error:
/* "stall" on error */
retval = -EPIPE;
}
spin_unlock_irqrestore(&xhci->lock, flags);
return retval;
}
/*
* Returns 0 if the status hasn't changed, or the number of bytes in buf.
* Ports are 0-indexed from the HCD point of view,
* and 1-indexed from the USB core pointer of view.
* xHCI instances can have up to 127 ports, so FIXME if you see more than 15.
*
* Note that the status change bits will be cleared as soon as a port status
* change event is generated, so we use the saved status from that event.
*/
int xhci_hub_status_data(struct usb_hcd *hcd, char *buf)
{
unsigned long flags;
u32 temp, status;
int i, retval;
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
int ports;
u32 __iomem *addr;
ports = HCS_MAX_PORTS(xhci->hcs_params1);
/* Initial status is no changes */
buf[0] = 0;
status = 0;
if (ports > 7) {
buf[1] = 0;
retval = 2;
} else {
retval = 1;
}
spin_lock_irqsave(&xhci->lock, flags);
/* For each port, did anything change? If so, set that bit in buf. */
for (i = 0; i < ports; i++) {
addr = &xhci->op_regs->port_status_base +
NUM_PORT_REGS*i;
temp = xhci_readl(xhci, addr);
if (temp & (PORT_CSC | PORT_PEC | PORT_OCC)) {
if (i < 7)
buf[0] |= 1 << (i + 1);
else
buf[1] |= 1 << (i - 7);
status = 1;
}
}
spin_unlock_irqrestore(&xhci->lock, flags);
return status ? retval : 0;
}

View File

@ -0,0 +1,769 @@
/*
* xHCI host controller driver
*
* Copyright (C) 2008 Intel Corp.
*
* Author: Sarah Sharp
* Some code borrowed from the Linux EHCI driver.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* 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/usb.h>
#include <linux/pci.h>
#include <linux/dmapool.h>
#include "xhci.h"
/*
* Allocates a generic ring segment from the ring pool, sets the dma address,
* initializes the segment to zero, and sets the private next pointer to NULL.
*
* Section 4.11.1.1:
* "All components of all Command and Transfer TRBs shall be initialized to '0'"
*/
static struct xhci_segment *xhci_segment_alloc(struct xhci_hcd *xhci, gfp_t flags)
{
struct xhci_segment *seg;
dma_addr_t dma;
seg = kzalloc(sizeof *seg, flags);
if (!seg)
return 0;
xhci_dbg(xhci, "Allocating priv segment structure at %p\n", seg);
seg->trbs = dma_pool_alloc(xhci->segment_pool, flags, &dma);
if (!seg->trbs) {
kfree(seg);
return 0;
}
xhci_dbg(xhci, "// Allocating segment at %p (virtual) 0x%llx (DMA)\n",
seg->trbs, (unsigned long long)dma);
memset(seg->trbs, 0, SEGMENT_SIZE);
seg->dma = dma;
seg->next = NULL;
return seg;
}
static void xhci_segment_free(struct xhci_hcd *xhci, struct xhci_segment *seg)
{
if (!seg)
return;
if (seg->trbs) {
xhci_dbg(xhci, "Freeing DMA segment at %p (virtual) 0x%llx (DMA)\n",
seg->trbs, (unsigned long long)seg->dma);
dma_pool_free(xhci->segment_pool, seg->trbs, seg->dma);
seg->trbs = NULL;
}
xhci_dbg(xhci, "Freeing priv segment structure at %p\n", seg);
kfree(seg);
}
/*
* Make the prev segment point to the next segment.
*
* Change the last TRB in the prev segment to be a Link TRB which points to the
* DMA address of the next segment. The caller needs to set any Link TRB
* related flags, such as End TRB, Toggle Cycle, and no snoop.
*/
static void xhci_link_segments(struct xhci_hcd *xhci, struct xhci_segment *prev,
struct xhci_segment *next, bool link_trbs)
{
u32 val;
if (!prev || !next)
return;
prev->next = next;
if (link_trbs) {
prev->trbs[TRBS_PER_SEGMENT-1].link.segment_ptr[0] = next->dma;
/* Set the last TRB in the segment to have a TRB type ID of Link TRB */
val = prev->trbs[TRBS_PER_SEGMENT-1].link.control;
val &= ~TRB_TYPE_BITMASK;
val |= TRB_TYPE(TRB_LINK);
prev->trbs[TRBS_PER_SEGMENT-1].link.control = val;
}
xhci_dbg(xhci, "Linking segment 0x%llx to segment 0x%llx (DMA)\n",
(unsigned long long)prev->dma,
(unsigned long long)next->dma);
}
/* XXX: Do we need the hcd structure in all these functions? */
void xhci_ring_free(struct xhci_hcd *xhci, struct xhci_ring *ring)
{
struct xhci_segment *seg;
struct xhci_segment *first_seg;
if (!ring || !ring->first_seg)
return;
first_seg = ring->first_seg;
seg = first_seg->next;
xhci_dbg(xhci, "Freeing ring at %p\n", ring);
while (seg != first_seg) {
struct xhci_segment *next = seg->next;
xhci_segment_free(xhci, seg);
seg = next;
}
xhci_segment_free(xhci, first_seg);
ring->first_seg = NULL;
kfree(ring);
}
/**
* Create a new ring with zero or more segments.
*
* Link each segment together into a ring.
* Set the end flag and the cycle toggle bit on the last segment.
* See section 4.9.1 and figures 15 and 16.
*/
static struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci,
unsigned int num_segs, bool link_trbs, gfp_t flags)
{
struct xhci_ring *ring;
struct xhci_segment *prev;
ring = kzalloc(sizeof *(ring), flags);
xhci_dbg(xhci, "Allocating ring at %p\n", ring);
if (!ring)
return 0;
INIT_LIST_HEAD(&ring->td_list);
INIT_LIST_HEAD(&ring->cancelled_td_list);
if (num_segs == 0)
return ring;
ring->first_seg = xhci_segment_alloc(xhci, flags);
if (!ring->first_seg)
goto fail;
num_segs--;
prev = ring->first_seg;
while (num_segs > 0) {
struct xhci_segment *next;
next = xhci_segment_alloc(xhci, flags);
if (!next)
goto fail;
xhci_link_segments(xhci, prev, next, link_trbs);
prev = next;
num_segs--;
}
xhci_link_segments(xhci, prev, ring->first_seg, link_trbs);
if (link_trbs) {
/* See section 4.9.2.1 and 6.4.4.1 */
prev->trbs[TRBS_PER_SEGMENT-1].link.control |= (LINK_TOGGLE);
xhci_dbg(xhci, "Wrote link toggle flag to"
" segment %p (virtual), 0x%llx (DMA)\n",
prev, (unsigned long long)prev->dma);
}
/* The ring is empty, so the enqueue pointer == dequeue pointer */
ring->enqueue = ring->first_seg->trbs;
ring->enq_seg = ring->first_seg;
ring->dequeue = ring->enqueue;
ring->deq_seg = ring->first_seg;
/* The ring is initialized to 0. The producer must write 1 to the cycle
* bit to handover ownership of the TRB, so PCS = 1. The consumer must
* compare CCS to the cycle bit to check ownership, so CCS = 1.
*/
ring->cycle_state = 1;
return ring;
fail:
xhci_ring_free(xhci, ring);
return 0;
}
/* All the xhci_tds in the ring's TD list should be freed at this point */
void xhci_free_virt_device(struct xhci_hcd *xhci, int slot_id)
{
struct xhci_virt_device *dev;
int i;
/* Slot ID 0 is reserved */
if (slot_id == 0 || !xhci->devs[slot_id])
return;
dev = xhci->devs[slot_id];
xhci->dcbaa->dev_context_ptrs[2*slot_id] = 0;
xhci->dcbaa->dev_context_ptrs[2*slot_id + 1] = 0;
if (!dev)
return;
for (i = 0; i < 31; ++i)
if (dev->ep_rings[i])
xhci_ring_free(xhci, dev->ep_rings[i]);
if (dev->in_ctx)
dma_pool_free(xhci->device_pool,
dev->in_ctx, dev->in_ctx_dma);
if (dev->out_ctx)
dma_pool_free(xhci->device_pool,
dev->out_ctx, dev->out_ctx_dma);
kfree(xhci->devs[slot_id]);
xhci->devs[slot_id] = 0;
}
int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id,
struct usb_device *udev, gfp_t flags)
{
dma_addr_t dma;
struct xhci_virt_device *dev;
/* Slot ID 0 is reserved */
if (slot_id == 0 || xhci->devs[slot_id]) {
xhci_warn(xhci, "Bad Slot ID %d\n", slot_id);
return 0;
}
xhci->devs[slot_id] = kzalloc(sizeof(*xhci->devs[slot_id]), flags);
if (!xhci->devs[slot_id])
return 0;
dev = xhci->devs[slot_id];
/* Allocate the (output) device context that will be used in the HC */
dev->out_ctx = dma_pool_alloc(xhci->device_pool, flags, &dma);
if (!dev->out_ctx)
goto fail;
dev->out_ctx_dma = dma;
xhci_dbg(xhci, "Slot %d output ctx = 0x%llx (dma)\n", slot_id,
(unsigned long long)dma);
memset(dev->out_ctx, 0, sizeof(*dev->out_ctx));
/* Allocate the (input) device context for address device command */
dev->in_ctx = dma_pool_alloc(xhci->device_pool, flags, &dma);
if (!dev->in_ctx)
goto fail;
dev->in_ctx_dma = dma;
xhci_dbg(xhci, "Slot %d input ctx = 0x%llx (dma)\n", slot_id,
(unsigned long long)dma);
memset(dev->in_ctx, 0, sizeof(*dev->in_ctx));
/* Allocate endpoint 0 ring */
dev->ep_rings[0] = xhci_ring_alloc(xhci, 1, true, flags);
if (!dev->ep_rings[0])
goto fail;
init_completion(&dev->cmd_completion);
/*
* Point to output device context in dcbaa; skip the output control
* context, which is eight 32 bit fields (or 32 bytes long)
*/
xhci->dcbaa->dev_context_ptrs[2*slot_id] =
(u32) dev->out_ctx_dma + (32);
xhci_dbg(xhci, "Set slot id %d dcbaa entry %p to 0x%llx\n",
slot_id,
&xhci->dcbaa->dev_context_ptrs[2*slot_id],
(unsigned long long)dev->out_ctx_dma);
xhci->dcbaa->dev_context_ptrs[2*slot_id + 1] = 0;
return 1;
fail:
xhci_free_virt_device(xhci, slot_id);
return 0;
}
/* Setup an xHCI virtual device for a Set Address command */
int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *udev)
{
struct xhci_virt_device *dev;
struct xhci_ep_ctx *ep0_ctx;
struct usb_device *top_dev;
dev = xhci->devs[udev->slot_id];
/* Slot ID 0 is reserved */
if (udev->slot_id == 0 || !dev) {
xhci_warn(xhci, "Slot ID %d is not assigned to this device\n",
udev->slot_id);
return -EINVAL;
}
ep0_ctx = &dev->in_ctx->ep[0];
/* 2) New slot context and endpoint 0 context are valid*/
dev->in_ctx->add_flags = SLOT_FLAG | EP0_FLAG;
/* 3) Only the control endpoint is valid - one endpoint context */
dev->in_ctx->slot.dev_info |= LAST_CTX(1);
switch (udev->speed) {
case USB_SPEED_SUPER:
dev->in_ctx->slot.dev_info |= (u32) udev->route;
dev->in_ctx->slot.dev_info |= (u32) SLOT_SPEED_SS;
break;
case USB_SPEED_HIGH:
dev->in_ctx->slot.dev_info |= (u32) SLOT_SPEED_HS;
break;
case USB_SPEED_FULL:
dev->in_ctx->slot.dev_info |= (u32) SLOT_SPEED_FS;
break;
case USB_SPEED_LOW:
dev->in_ctx->slot.dev_info |= (u32) SLOT_SPEED_LS;
break;
case USB_SPEED_VARIABLE:
xhci_dbg(xhci, "FIXME xHCI doesn't support wireless speeds\n");
return -EINVAL;
break;
default:
/* Speed was set earlier, this shouldn't happen. */
BUG();
}
/* Find the root hub port this device is under */
for (top_dev = udev; top_dev->parent && top_dev->parent->parent;
top_dev = top_dev->parent)
/* Found device below root hub */;
dev->in_ctx->slot.dev_info2 |= (u32) ROOT_HUB_PORT(top_dev->portnum);
xhci_dbg(xhci, "Set root hub portnum to %d\n", top_dev->portnum);
/* Is this a LS/FS device under a HS hub? */
/*
* FIXME: I don't think this is right, where does the TT info for the
* roothub or parent hub come from?
*/
if ((udev->speed == USB_SPEED_LOW || udev->speed == USB_SPEED_FULL) &&
udev->tt) {
dev->in_ctx->slot.tt_info = udev->tt->hub->slot_id;
dev->in_ctx->slot.tt_info |= udev->ttport << 8;
}
xhci_dbg(xhci, "udev->tt = %p\n", udev->tt);
xhci_dbg(xhci, "udev->ttport = 0x%x\n", udev->ttport);
/* Step 4 - ring already allocated */
/* Step 5 */
ep0_ctx->ep_info2 = EP_TYPE(CTRL_EP);
/*
* See section 4.3 bullet 6:
* The default Max Packet size for ep0 is "8 bytes for a USB2
* LS/FS/HS device or 512 bytes for a USB3 SS device"
* XXX: Not sure about wireless USB devices.
*/
if (udev->speed == USB_SPEED_SUPER)
ep0_ctx->ep_info2 |= MAX_PACKET(512);
else
ep0_ctx->ep_info2 |= MAX_PACKET(8);
/* EP 0 can handle "burst" sizes of 1, so Max Burst Size field is 0 */
ep0_ctx->ep_info2 |= MAX_BURST(0);
ep0_ctx->ep_info2 |= ERROR_COUNT(3);
ep0_ctx->deq[0] =
dev->ep_rings[0]->first_seg->dma;
ep0_ctx->deq[0] |= dev->ep_rings[0]->cycle_state;
ep0_ctx->deq[1] = 0;
/* Steps 7 and 8 were done in xhci_alloc_virt_device() */
return 0;
}
/* Return the polling or NAK interval.
*
* The polling interval is expressed in "microframes". If xHCI's Interval field
* is set to N, it will service the endpoint every 2^(Interval)*125us.
*
* The NAK interval is one NAK per 1 to 255 microframes, or no NAKs if interval
* is set to 0.
*/
static inline unsigned int xhci_get_endpoint_interval(struct usb_device *udev,
struct usb_host_endpoint *ep)
{
unsigned int interval = 0;
switch (udev->speed) {
case USB_SPEED_HIGH:
/* Max NAK rate */
if (usb_endpoint_xfer_control(&ep->desc) ||
usb_endpoint_xfer_bulk(&ep->desc))
interval = ep->desc.bInterval;
/* Fall through - SS and HS isoc/int have same decoding */
case USB_SPEED_SUPER:
if (usb_endpoint_xfer_int(&ep->desc) ||
usb_endpoint_xfer_isoc(&ep->desc)) {
if (ep->desc.bInterval == 0)
interval = 0;
else
interval = ep->desc.bInterval - 1;
if (interval > 15)
interval = 15;
if (interval != ep->desc.bInterval + 1)
dev_warn(&udev->dev, "ep %#x - rounding interval to %d microframes\n",
ep->desc.bEndpointAddress, 1 << interval);
}
break;
/* Convert bInterval (in 1-255 frames) to microframes and round down to
* nearest power of 2.
*/
case USB_SPEED_FULL:
case USB_SPEED_LOW:
if (usb_endpoint_xfer_int(&ep->desc) ||
usb_endpoint_xfer_isoc(&ep->desc)) {
interval = fls(8*ep->desc.bInterval) - 1;
if (interval > 10)
interval = 10;
if (interval < 3)
interval = 3;
if ((1 << interval) != 8*ep->desc.bInterval)
dev_warn(&udev->dev, "ep %#x - rounding interval to %d microframes\n",
ep->desc.bEndpointAddress, 1 << interval);
}
break;
default:
BUG();
}
return EP_INTERVAL(interval);
}
static inline u32 xhci_get_endpoint_type(struct usb_device *udev,
struct usb_host_endpoint *ep)
{
int in;
u32 type;
in = usb_endpoint_dir_in(&ep->desc);
if (usb_endpoint_xfer_control(&ep->desc)) {
type = EP_TYPE(CTRL_EP);
} else if (usb_endpoint_xfer_bulk(&ep->desc)) {
if (in)
type = EP_TYPE(BULK_IN_EP);
else
type = EP_TYPE(BULK_OUT_EP);
} else if (usb_endpoint_xfer_isoc(&ep->desc)) {
if (in)
type = EP_TYPE(ISOC_IN_EP);
else
type = EP_TYPE(ISOC_OUT_EP);
} else if (usb_endpoint_xfer_int(&ep->desc)) {
if (in)
type = EP_TYPE(INT_IN_EP);
else
type = EP_TYPE(INT_OUT_EP);
} else {
BUG();
}
return type;
}
int xhci_endpoint_init(struct xhci_hcd *xhci,
struct xhci_virt_device *virt_dev,
struct usb_device *udev,
struct usb_host_endpoint *ep,
gfp_t mem_flags)
{
unsigned int ep_index;
struct xhci_ep_ctx *ep_ctx;
struct xhci_ring *ep_ring;
unsigned int max_packet;
unsigned int max_burst;
ep_index = xhci_get_endpoint_index(&ep->desc);
ep_ctx = &virt_dev->in_ctx->ep[ep_index];
/* Set up the endpoint ring */
virt_dev->new_ep_rings[ep_index] = xhci_ring_alloc(xhci, 1, true, mem_flags);
if (!virt_dev->new_ep_rings[ep_index])
return -ENOMEM;
ep_ring = virt_dev->new_ep_rings[ep_index];
ep_ctx->deq[0] = ep_ring->first_seg->dma | ep_ring->cycle_state;
ep_ctx->deq[1] = 0;
ep_ctx->ep_info = xhci_get_endpoint_interval(udev, ep);
/* FIXME dig Mult and streams info out of ep companion desc */
/* Allow 3 retries for everything but isoc */
if (!usb_endpoint_xfer_isoc(&ep->desc))
ep_ctx->ep_info2 = ERROR_COUNT(3);
else
ep_ctx->ep_info2 = ERROR_COUNT(0);
ep_ctx->ep_info2 |= xhci_get_endpoint_type(udev, ep);
/* Set the max packet size and max burst */
switch (udev->speed) {
case USB_SPEED_SUPER:
max_packet = ep->desc.wMaxPacketSize;
ep_ctx->ep_info2 |= MAX_PACKET(max_packet);
/* dig out max burst from ep companion desc */
max_packet = ep->ss_ep_comp->desc.bMaxBurst;
ep_ctx->ep_info2 |= MAX_BURST(max_packet);
break;
case USB_SPEED_HIGH:
/* bits 11:12 specify the number of additional transaction
* opportunities per microframe (USB 2.0, section 9.6.6)
*/
if (usb_endpoint_xfer_isoc(&ep->desc) ||
usb_endpoint_xfer_int(&ep->desc)) {
max_burst = (ep->desc.wMaxPacketSize & 0x1800) >> 11;
ep_ctx->ep_info2 |= MAX_BURST(max_burst);
}
/* Fall through */
case USB_SPEED_FULL:
case USB_SPEED_LOW:
max_packet = ep->desc.wMaxPacketSize & 0x3ff;
ep_ctx->ep_info2 |= MAX_PACKET(max_packet);
break;
default:
BUG();
}
/* FIXME Debug endpoint context */
return 0;
}
void xhci_endpoint_zero(struct xhci_hcd *xhci,
struct xhci_virt_device *virt_dev,
struct usb_host_endpoint *ep)
{
unsigned int ep_index;
struct xhci_ep_ctx *ep_ctx;
ep_index = xhci_get_endpoint_index(&ep->desc);
ep_ctx = &virt_dev->in_ctx->ep[ep_index];
ep_ctx->ep_info = 0;
ep_ctx->ep_info2 = 0;
ep_ctx->deq[0] = 0;
ep_ctx->deq[1] = 0;
ep_ctx->tx_info = 0;
/* Don't free the endpoint ring until the set interface or configuration
* request succeeds.
*/
}
void xhci_mem_cleanup(struct xhci_hcd *xhci)
{
struct pci_dev *pdev = to_pci_dev(xhci_to_hcd(xhci)->self.controller);
int size;
int i;
/* Free the Event Ring Segment Table and the actual Event Ring */
xhci_writel(xhci, 0, &xhci->ir_set->erst_size);
xhci_writel(xhci, 0, &xhci->ir_set->erst_base[0]);
xhci_writel(xhci, 0, &xhci->ir_set->erst_base[1]);
xhci_writel(xhci, 0, &xhci->ir_set->erst_dequeue[0]);
xhci_writel(xhci, 0, &xhci->ir_set->erst_dequeue[1]);
size = sizeof(struct xhci_erst_entry)*(xhci->erst.num_entries);
if (xhci->erst.entries)
pci_free_consistent(pdev, size,
xhci->erst.entries, xhci->erst.erst_dma_addr);
xhci->erst.entries = NULL;
xhci_dbg(xhci, "Freed ERST\n");
if (xhci->event_ring)
xhci_ring_free(xhci, xhci->event_ring);
xhci->event_ring = NULL;
xhci_dbg(xhci, "Freed event ring\n");
xhci_writel(xhci, 0, &xhci->op_regs->cmd_ring[0]);
xhci_writel(xhci, 0, &xhci->op_regs->cmd_ring[1]);
if (xhci->cmd_ring)
xhci_ring_free(xhci, xhci->cmd_ring);
xhci->cmd_ring = NULL;
xhci_dbg(xhci, "Freed command ring\n");
for (i = 1; i < MAX_HC_SLOTS; ++i)
xhci_free_virt_device(xhci, i);
if (xhci->segment_pool)
dma_pool_destroy(xhci->segment_pool);
xhci->segment_pool = NULL;
xhci_dbg(xhci, "Freed segment pool\n");
if (xhci->device_pool)
dma_pool_destroy(xhci->device_pool);
xhci->device_pool = NULL;
xhci_dbg(xhci, "Freed device context pool\n");
xhci_writel(xhci, 0, &xhci->op_regs->dcbaa_ptr[0]);
xhci_writel(xhci, 0, &xhci->op_regs->dcbaa_ptr[1]);
if (xhci->dcbaa)
pci_free_consistent(pdev, sizeof(*xhci->dcbaa),
xhci->dcbaa, xhci->dcbaa->dma);
xhci->dcbaa = NULL;
xhci->page_size = 0;
xhci->page_shift = 0;
}
int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
{
dma_addr_t dma;
struct device *dev = xhci_to_hcd(xhci)->self.controller;
unsigned int val, val2;
struct xhci_segment *seg;
u32 page_size;
int i;
page_size = xhci_readl(xhci, &xhci->op_regs->page_size);
xhci_dbg(xhci, "Supported page size register = 0x%x\n", page_size);
for (i = 0; i < 16; i++) {
if ((0x1 & page_size) != 0)
break;
page_size = page_size >> 1;
}
if (i < 16)
xhci_dbg(xhci, "Supported page size of %iK\n", (1 << (i+12)) / 1024);
else
xhci_warn(xhci, "WARN: no supported page size\n");
/* Use 4K pages, since that's common and the minimum the HC supports */
xhci->page_shift = 12;
xhci->page_size = 1 << xhci->page_shift;
xhci_dbg(xhci, "HCD page size set to %iK\n", xhci->page_size / 1024);
/*
* Program the Number of Device Slots Enabled field in the CONFIG
* register with the max value of slots the HC can handle.
*/
val = HCS_MAX_SLOTS(xhci_readl(xhci, &xhci->cap_regs->hcs_params1));
xhci_dbg(xhci, "// xHC can handle at most %d device slots.\n",
(unsigned int) val);
val2 = xhci_readl(xhci, &xhci->op_regs->config_reg);
val |= (val2 & ~HCS_SLOTS_MASK);
xhci_dbg(xhci, "// Setting Max device slots reg = 0x%x.\n",
(unsigned int) val);
xhci_writel(xhci, val, &xhci->op_regs->config_reg);
/*
* Section 5.4.8 - doorbell array must be
* "physically contiguous and 64-byte (cache line) aligned".
*/
xhci->dcbaa = pci_alloc_consistent(to_pci_dev(dev),
sizeof(*xhci->dcbaa), &dma);
if (!xhci->dcbaa)
goto fail;
memset(xhci->dcbaa, 0, sizeof *(xhci->dcbaa));
xhci->dcbaa->dma = dma;
xhci_dbg(xhci, "// Device context base array address = 0x%llx (DMA), %p (virt)\n",
(unsigned long long)xhci->dcbaa->dma, xhci->dcbaa);
xhci_writel(xhci, dma, &xhci->op_regs->dcbaa_ptr[0]);
xhci_writel(xhci, (u32) 0, &xhci->op_regs->dcbaa_ptr[1]);
/*
* Initialize the ring segment pool. The ring must be a contiguous
* structure comprised of TRBs. The TRBs must be 16 byte aligned,
* however, the command ring segment needs 64-byte aligned segments,
* so we pick the greater alignment need.
*/
xhci->segment_pool = dma_pool_create("xHCI ring segments", dev,
SEGMENT_SIZE, 64, xhci->page_size);
/* See Table 46 and Note on Figure 55 */
/* FIXME support 64-byte contexts */
xhci->device_pool = dma_pool_create("xHCI input/output contexts", dev,
sizeof(struct xhci_device_control),
64, xhci->page_size);
if (!xhci->segment_pool || !xhci->device_pool)
goto fail;
/* Set up the command ring to have one segments for now. */
xhci->cmd_ring = xhci_ring_alloc(xhci, 1, true, flags);
if (!xhci->cmd_ring)
goto fail;
xhci_dbg(xhci, "Allocated command ring at %p\n", xhci->cmd_ring);
xhci_dbg(xhci, "First segment DMA is 0x%llx\n",
(unsigned long long)xhci->cmd_ring->first_seg->dma);
/* Set the address in the Command Ring Control register */
val = xhci_readl(xhci, &xhci->op_regs->cmd_ring[0]);
val = (val & ~CMD_RING_ADDR_MASK) |
(xhci->cmd_ring->first_seg->dma & CMD_RING_ADDR_MASK) |
xhci->cmd_ring->cycle_state;
xhci_dbg(xhci, "// Setting command ring address low bits to 0x%x\n", val);
xhci_writel(xhci, val, &xhci->op_regs->cmd_ring[0]);
xhci_dbg(xhci, "// Setting command ring address high bits to 0x0\n");
xhci_writel(xhci, (u32) 0, &xhci->op_regs->cmd_ring[1]);
xhci_dbg_cmd_ptrs(xhci);
val = xhci_readl(xhci, &xhci->cap_regs->db_off);
val &= DBOFF_MASK;
xhci_dbg(xhci, "// Doorbell array is located at offset 0x%x"
" from cap regs base addr\n", val);
xhci->dba = (void *) xhci->cap_regs + val;
xhci_dbg_regs(xhci);
xhci_print_run_regs(xhci);
/* Set ir_set to interrupt register set 0 */
xhci->ir_set = (void *) xhci->run_regs->ir_set;
/*
* Event ring setup: Allocate a normal ring, but also setup
* the event ring segment table (ERST). Section 4.9.3.
*/
xhci_dbg(xhci, "// Allocating event ring\n");
xhci->event_ring = xhci_ring_alloc(xhci, ERST_NUM_SEGS, false, flags);
if (!xhci->event_ring)
goto fail;
xhci->erst.entries = pci_alloc_consistent(to_pci_dev(dev),
sizeof(struct xhci_erst_entry)*ERST_NUM_SEGS, &dma);
if (!xhci->erst.entries)
goto fail;
xhci_dbg(xhci, "// Allocated event ring segment table at 0x%llx\n",
(unsigned long long)dma);
memset(xhci->erst.entries, 0, sizeof(struct xhci_erst_entry)*ERST_NUM_SEGS);
xhci->erst.num_entries = ERST_NUM_SEGS;
xhci->erst.erst_dma_addr = dma;
xhci_dbg(xhci, "Set ERST to 0; private num segs = %i, virt addr = %p, dma addr = 0x%llx\n",
xhci->erst.num_entries,
xhci->erst.entries,
(unsigned long long)xhci->erst.erst_dma_addr);
/* set ring base address and size for each segment table entry */
for (val = 0, seg = xhci->event_ring->first_seg; val < ERST_NUM_SEGS; val++) {
struct xhci_erst_entry *entry = &xhci->erst.entries[val];
entry->seg_addr[0] = seg->dma;
entry->seg_addr[1] = 0;
entry->seg_size = TRBS_PER_SEGMENT;
entry->rsvd = 0;
seg = seg->next;
}
/* set ERST count with the number of entries in the segment table */
val = xhci_readl(xhci, &xhci->ir_set->erst_size);
val &= ERST_SIZE_MASK;
val |= ERST_NUM_SEGS;
xhci_dbg(xhci, "// Write ERST size = %i to ir_set 0 (some bits preserved)\n",
val);
xhci_writel(xhci, val, &xhci->ir_set->erst_size);
xhci_dbg(xhci, "// Set ERST entries to point to event ring.\n");
/* set the segment table base address */
xhci_dbg(xhci, "// Set ERST base address for ir_set 0 = 0x%llx\n",
(unsigned long long)xhci->erst.erst_dma_addr);
val = xhci_readl(xhci, &xhci->ir_set->erst_base[0]);
val &= ERST_PTR_MASK;
val |= (xhci->erst.erst_dma_addr & ~ERST_PTR_MASK);
xhci_writel(xhci, val, &xhci->ir_set->erst_base[0]);
xhci_writel(xhci, 0, &xhci->ir_set->erst_base[1]);
/* Set the event ring dequeue address */
xhci_set_hc_event_deq(xhci);
xhci_dbg(xhci, "Wrote ERST address to ir_set 0.\n");
xhci_print_ir_set(xhci, xhci->ir_set, 0);
/*
* XXX: Might need to set the Interrupter Moderation Register to
* something other than the default (~1ms minimum between interrupts).
* See section 5.5.1.2.
*/
init_completion(&xhci->addr_dev);
for (i = 0; i < MAX_HC_SLOTS; ++i)
xhci->devs[i] = 0;
return 0;
fail:
xhci_warn(xhci, "Couldn't initialize memory\n");
xhci_mem_cleanup(xhci);
return -ENOMEM;
}

View File

@ -0,0 +1,166 @@
/*
* xHCI host controller driver PCI Bus Glue.
*
* Copyright (C) 2008 Intel Corp.
*
* Author: Sarah Sharp
* Some code borrowed from the Linux EHCI driver.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* 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/pci.h>
#include "xhci.h"
static const char hcd_name[] = "xhci_hcd";
/* called after powerup, by probe or system-pm "wakeup" */
static int xhci_pci_reinit(struct xhci_hcd *xhci, struct pci_dev *pdev)
{
/*
* TODO: Implement finding debug ports later.
* TODO: see if there are any quirks that need to be added to handle
* new extended capabilities.
*/
/* PCI Memory-Write-Invalidate cycle support is optional (uncommon) */
if (!pci_set_mwi(pdev))
xhci_dbg(xhci, "MWI active\n");
xhci_dbg(xhci, "Finished xhci_pci_reinit\n");
return 0;
}
/* called during probe() after chip reset completes */
static int xhci_pci_setup(struct usb_hcd *hcd)
{
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
int retval;
xhci->cap_regs = hcd->regs;
xhci->op_regs = hcd->regs +
HC_LENGTH(xhci_readl(xhci, &xhci->cap_regs->hc_capbase));
xhci->run_regs = hcd->regs +
(xhci_readl(xhci, &xhci->cap_regs->run_regs_off) & RTSOFF_MASK);
/* Cache read-only capability registers */
xhci->hcs_params1 = xhci_readl(xhci, &xhci->cap_regs->hcs_params1);
xhci->hcs_params2 = xhci_readl(xhci, &xhci->cap_regs->hcs_params2);
xhci->hcs_params3 = xhci_readl(xhci, &xhci->cap_regs->hcs_params3);
xhci->hcc_params = xhci_readl(xhci, &xhci->cap_regs->hcc_params);
xhci_print_registers(xhci);
/* Make sure the HC is halted. */
retval = xhci_halt(xhci);
if (retval)
return retval;
xhci_dbg(xhci, "Resetting HCD\n");
/* Reset the internal HC memory state and registers. */
retval = xhci_reset(xhci);
if (retval)
return retval;
xhci_dbg(xhci, "Reset complete\n");
xhci_dbg(xhci, "Calling HCD init\n");
/* Initialize HCD and host controller data structures. */
retval = xhci_init(hcd);
if (retval)
return retval;
xhci_dbg(xhci, "Called HCD init\n");
pci_read_config_byte(pdev, XHCI_SBRN_OFFSET, &xhci->sbrn);
xhci_dbg(xhci, "Got SBRN %u\n", (unsigned int) xhci->sbrn);
/* Find any debug ports */
return xhci_pci_reinit(xhci, pdev);
}
static const struct hc_driver xhci_pci_hc_driver = {
.description = hcd_name,
.product_desc = "xHCI Host Controller",
.hcd_priv_size = sizeof(struct xhci_hcd),
/*
* generic hardware linkage
*/
.irq = xhci_irq,
.flags = HCD_MEMORY | HCD_USB3,
/*
* basic lifecycle operations
*/
.reset = xhci_pci_setup,
.start = xhci_run,
/* suspend and resume implemented later */
.stop = xhci_stop,
.shutdown = xhci_shutdown,
/*
* managing i/o requests and associated device resources
*/
.urb_enqueue = xhci_urb_enqueue,
.urb_dequeue = xhci_urb_dequeue,
.alloc_dev = xhci_alloc_dev,
.free_dev = xhci_free_dev,
.add_endpoint = xhci_add_endpoint,
.drop_endpoint = xhci_drop_endpoint,
.check_bandwidth = xhci_check_bandwidth,
.reset_bandwidth = xhci_reset_bandwidth,
.address_device = xhci_address_device,
/*
* scheduling support
*/
.get_frame_number = xhci_get_frame,
/* Root hub support */
.hub_control = xhci_hub_control,
.hub_status_data = xhci_hub_status_data,
};
/*-------------------------------------------------------------------------*/
/* PCI driver selection metadata; PCI hotplugging uses this */
static const struct pci_device_id pci_ids[] = { {
/* handle any USB 3.0 xHCI controller */
PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_USB_XHCI, ~0),
.driver_data = (unsigned long) &xhci_pci_hc_driver,
},
{ /* end: all zeroes */ }
};
MODULE_DEVICE_TABLE(pci, pci_ids);
/* pci driver glue; this is a "new style" PCI driver module */
static struct pci_driver xhci_pci_driver = {
.name = (char *) hcd_name,
.id_table = pci_ids,
.probe = usb_hcd_pci_probe,
.remove = usb_hcd_pci_remove,
/* suspend and resume implemented later */
.shutdown = usb_hcd_pci_shutdown,
};
int xhci_register_pci()
{
return pci_register_driver(&xhci_pci_driver);
}
void xhci_unregister_pci()
{
pci_unregister_driver(&xhci_pci_driver);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
config USB_SISUSBVGA
tristate "USB 2.0 SVGA dongle support (Net2280/SiS315)"
depends on USB && USB_EHCI_HCD
depends on USB && (USB_MUSB_HDRC || USB_EHCI_HCD)
---help---
Say Y here if you intend to attach a USB2VGA dongle based on a
Net2280 and a SiS315 chip.

View File

@ -1072,23 +1072,34 @@ static int unlink1 (struct usbtest_dev *dev, int pipe, int size, int async)
*/
msleep (jiffies % (2 * INTERRUPT_RATE));
if (async) {
retry:
retval = usb_unlink_urb (urb);
if (retval == -EBUSY || retval == -EIDRM) {
/* we can't unlink urbs while they're completing.
* or if they've completed, and we haven't resubmitted.
* "normal" drivers would prevent resubmission, but
* since we're testing unlink paths, we can't.
*/
ERROR(dev, "unlink retry\n");
goto retry;
while (!completion_done(&completion)) {
retval = usb_unlink_urb(urb);
switch (retval) {
case -EBUSY:
case -EIDRM:
/* we can't unlink urbs while they're completing
* or if they've completed, and we haven't
* resubmitted. "normal" drivers would prevent
* resubmission, but since we're testing unlink
* paths, we can't.
*/
ERROR(dev, "unlink retry\n");
continue;
case 0:
case -EINPROGRESS:
break;
default:
dev_err(&dev->intf->dev,
"unlink fail %d\n", retval);
return retval;
}
break;
}
} else
usb_kill_urb (urb);
if (!(retval == 0 || retval == -EINPROGRESS)) {
dev_err(&dev->intf->dev, "unlink fail %d\n", retval);
return retval;
}
wait_for_completion (&completion);
retval = urb->status;

View File

@ -733,7 +733,7 @@ int __init mon_text_init(void)
{
struct dentry *mondir;
mondir = debugfs_create_dir("usbmon", NULL);
mondir = debugfs_create_dir("usbmon", usb_debug_root);
if (IS_ERR(mondir)) {
printk(KERN_NOTICE TAG ": debugfs is not available\n");
return -ENODEV;

View File

@ -10,6 +10,7 @@ comment "Enable Host or Gadget support to see Inventra options"
config USB_MUSB_HDRC
depends on (USB || USB_GADGET) && HAVE_CLK
depends on !SUPERH
select NOP_USB_XCEIV if ARCH_DAVINCI
select TWL4030_USB if MACH_OMAP_3430SDP
select USB_OTG_UTILS
tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)'
@ -55,6 +56,7 @@ comment "Blackfin high speed USB Support"
config USB_TUSB6010
boolean "TUSB 6010 support"
depends on USB_MUSB_HDRC && !USB_MUSB_SOC
select NOP_USB_XCEIV
default y
help
The TUSB 6010 chip, from Texas Instruments, connects a discrete

View File

@ -143,7 +143,7 @@ static void musb_conn_timer_handler(unsigned long _musb)
u16 val;
spin_lock_irqsave(&musb->lock, flags);
switch (musb->xceiv.state) {
switch (musb->xceiv->state) {
case OTG_STATE_A_IDLE:
case OTG_STATE_A_WAIT_BCON:
/* Start a new session */
@ -154,7 +154,7 @@ static void musb_conn_timer_handler(unsigned long _musb)
val = musb_readw(musb->mregs, MUSB_DEVCTL);
if (!(val & MUSB_DEVCTL_BDEVICE)) {
gpio_set_value(musb->config->gpio_vrsel, 1);
musb->xceiv.state = OTG_STATE_A_WAIT_BCON;
musb->xceiv->state = OTG_STATE_A_WAIT_BCON;
} else {
gpio_set_value(musb->config->gpio_vrsel, 0);
@ -247,6 +247,11 @@ int __init musb_platform_init(struct musb *musb)
}
gpio_direction_output(musb->config->gpio_vrsel, 0);
usb_nop_xceiv_register();
musb->xceiv = otg_get_transceiver();
if (!musb->xceiv)
return -ENODEV;
if (ANOMALY_05000346) {
bfin_write_USB_APHY_CALIB(ANOMALY_05000346_value);
SSYNC();
@ -291,7 +296,7 @@ int __init musb_platform_init(struct musb *musb)
musb_conn_timer_handler, (unsigned long) musb);
}
if (is_peripheral_enabled(musb))
musb->xceiv.set_power = bfin_set_power;
musb->xceiv->set_power = bfin_set_power;
musb->isr = blackfin_interrupt;

View File

@ -6,6 +6,7 @@
* The TUSB6020, using VLYNQ, has CPPI that looks much like DaVinci.
*/
#include <linux/platform_device.h>
#include <linux/usb.h>
#include "musb_core.h"
@ -1145,17 +1146,27 @@ static bool cppi_rx_scan(struct cppi *cppi, unsigned ch)
return completed;
}
void cppi_completion(struct musb *musb, u32 rx, u32 tx)
irqreturn_t cppi_interrupt(int irq, void *dev_id)
{
void __iomem *tibase;
int i, index;
struct musb *musb = dev_id;
struct cppi *cppi;
void __iomem *tibase;
struct musb_hw_ep *hw_ep = NULL;
u32 rx, tx;
int i, index;
cppi = container_of(musb->dma_controller, struct cppi, controller);
tibase = musb->ctrl_base;
tx = musb_readl(tibase, DAVINCI_TXCPPI_MASKED_REG);
rx = musb_readl(tibase, DAVINCI_RXCPPI_MASKED_REG);
if (!tx && !rx)
return IRQ_NONE;
DBG(4, "CPPI IRQ Tx%x Rx%x\n", tx, rx);
/* process TX channels */
for (index = 0; tx; tx = tx >> 1, index++) {
struct cppi_channel *tx_ch;
@ -1273,6 +1284,8 @@ void cppi_completion(struct musb *musb, u32 rx, u32 tx)
/* write to CPPI EOI register to re-enable interrupts */
musb_writel(tibase, DAVINCI_CPPI_EOI_REG, 0);
return IRQ_HANDLED;
}
/* Instantiate a software object representing a DMA controller. */
@ -1280,6 +1293,9 @@ struct dma_controller *__init
dma_controller_create(struct musb *musb, void __iomem *mregs)
{
struct cppi *controller;
struct device *dev = musb->controller;
struct platform_device *pdev = to_platform_device(dev);
int irq = platform_get_irq(pdev, 1);
controller = kzalloc(sizeof *controller, GFP_KERNEL);
if (!controller)
@ -1310,6 +1326,15 @@ dma_controller_create(struct musb *musb, void __iomem *mregs)
return NULL;
}
if (irq > 0) {
if (request_irq(irq, cppi_interrupt, 0, "cppi-dma", musb)) {
dev_err(dev, "request_irq %d failed!\n", irq);
dma_controller_destroy(&controller->controller);
return NULL;
}
controller->irq = irq;
}
return &controller->controller;
}
@ -1322,6 +1347,9 @@ void dma_controller_destroy(struct dma_controller *c)
cppi = container_of(c, struct cppi, controller);
if (cppi->irq)
free_irq(cppi->irq, cppi->musb);
/* assert: caller stopped the controller first */
dma_pool_destroy(cppi->pool);

View File

@ -119,6 +119,8 @@ struct cppi {
void __iomem *mregs; /* Mentor regs */
void __iomem *tibase; /* TI/CPPI regs */
int irq;
struct cppi_channel tx[4];
struct cppi_channel rx[4];
@ -127,7 +129,7 @@ struct cppi {
struct list_head tx_complete;
};
/* irq handling hook */
extern void cppi_completion(struct musb *, u32 rx, u32 tx);
/* CPPI IRQ handler */
extern irqreturn_t cppi_interrupt(int, void *);
#endif /* end of ifndef _CPPI_DMA_H_ */

View File

@ -215,7 +215,7 @@ static void otg_timer(unsigned long _musb)
DBG(7, "poll devctl %02x (%s)\n", devctl, otg_state_string(musb));
spin_lock_irqsave(&musb->lock, flags);
switch (musb->xceiv.state) {
switch (musb->xceiv->state) {
case OTG_STATE_A_WAIT_VFALL:
/* Wait till VBUS falls below SessionEnd (~0.2V); the 1.3 RTL
* seems to mis-handle session "start" otherwise (or in our
@ -226,7 +226,7 @@ static void otg_timer(unsigned long _musb)
mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
break;
}
musb->xceiv.state = OTG_STATE_A_WAIT_VRISE;
musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
musb_writel(musb->ctrl_base, DAVINCI_USB_INT_SET_REG,
MUSB_INTR_VBUSERROR << DAVINCI_USB_USBINT_SHIFT);
break;
@ -251,7 +251,7 @@ static void otg_timer(unsigned long _musb)
if (devctl & MUSB_DEVCTL_BDEVICE)
mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
else
musb->xceiv.state = OTG_STATE_A_IDLE;
musb->xceiv->state = OTG_STATE_A_IDLE;
break;
default:
break;
@ -265,6 +265,7 @@ static irqreturn_t davinci_interrupt(int irq, void *__hci)
irqreturn_t retval = IRQ_NONE;
struct musb *musb = __hci;
void __iomem *tibase = musb->ctrl_base;
struct cppi *cppi;
u32 tmp;
spin_lock_irqsave(&musb->lock, flags);
@ -281,16 +282,9 @@ static irqreturn_t davinci_interrupt(int irq, void *__hci)
/* CPPI interrupts share the same IRQ line, but have their own
* mask, state, "vector", and EOI registers.
*/
if (is_cppi_enabled()) {
u32 cppi_tx = musb_readl(tibase, DAVINCI_TXCPPI_MASKED_REG);
u32 cppi_rx = musb_readl(tibase, DAVINCI_RXCPPI_MASKED_REG);
if (cppi_tx || cppi_rx) {
DBG(4, "CPPI IRQ t%x r%x\n", cppi_tx, cppi_rx);
cppi_completion(musb, cppi_rx, cppi_tx);
retval = IRQ_HANDLED;
}
}
cppi = container_of(musb->dma_controller, struct cppi, controller);
if (is_cppi_enabled() && musb->dma_controller && !cppi->irq)
retval = cppi_interrupt(irq, __hci);
/* ack and handle non-CPPI interrupts */
tmp = musb_readl(tibase, DAVINCI_USB_INT_SRC_MASKED_REG);
@ -331,21 +325,21 @@ static irqreturn_t davinci_interrupt(int irq, void *__hci)
* to stop registering in devctl.
*/
musb->int_usb &= ~MUSB_INTR_VBUSERROR;
musb->xceiv.state = OTG_STATE_A_WAIT_VFALL;
musb->xceiv->state = OTG_STATE_A_WAIT_VFALL;
mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
WARNING("VBUS error workaround (delay coming)\n");
} else if (is_host_enabled(musb) && drvvbus) {
musb->is_active = 1;
MUSB_HST_MODE(musb);
musb->xceiv.default_a = 1;
musb->xceiv.state = OTG_STATE_A_WAIT_VRISE;
musb->xceiv->default_a = 1;
musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
portstate(musb->port1_status |= USB_PORT_STAT_POWER);
del_timer(&otg_workaround);
} else {
musb->is_active = 0;
MUSB_DEV_MODE(musb);
musb->xceiv.default_a = 0;
musb->xceiv.state = OTG_STATE_B_IDLE;
musb->xceiv->default_a = 0;
musb->xceiv->state = OTG_STATE_B_IDLE;
portstate(musb->port1_status &= ~USB_PORT_STAT_POWER);
}
@ -367,17 +361,12 @@ static irqreturn_t davinci_interrupt(int irq, void *__hci)
/* poll for ID change */
if (is_otg_enabled(musb)
&& musb->xceiv.state == OTG_STATE_B_IDLE)
&& musb->xceiv->state == OTG_STATE_B_IDLE)
mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ);
spin_unlock_irqrestore(&musb->lock, flags);
/* REVISIT we sometimes get unhandled IRQs
* (e.g. ep0). not clear why...
*/
if (retval != IRQ_HANDLED)
DBG(5, "unhandled? %08x\n", tmp);
return IRQ_HANDLED;
return retval;
}
int musb_platform_set_mode(struct musb *musb, u8 mode)
@ -391,6 +380,11 @@ int __init musb_platform_init(struct musb *musb)
void __iomem *tibase = musb->ctrl_base;
u32 revision;
usb_nop_xceiv_register();
musb->xceiv = otg_get_transceiver();
if (!musb->xceiv)
return -ENODEV;
musb->mregs += DAVINCI_BASE_OFFSET;
clk_enable(musb->clock);
@ -398,7 +392,7 @@ int __init musb_platform_init(struct musb *musb)
/* returns zero if e.g. not clocked */
revision = musb_readl(tibase, DAVINCI_USB_VERSION_REG);
if (revision == 0)
return -ENODEV;
goto fail;
if (is_host_enabled(musb))
setup_timer(&otg_workaround, otg_timer, (unsigned long) musb);
@ -432,6 +426,10 @@ int __init musb_platform_init(struct musb *musb)
musb->isr = davinci_interrupt;
return 0;
fail:
usb_nop_xceiv_unregister();
return -ENODEV;
}
int musb_platform_exit(struct musb *musb)
@ -442,7 +440,7 @@ int musb_platform_exit(struct musb *musb)
davinci_source_power(musb, 0 /*off*/, 1);
/* delay, to avoid problems with module reload */
if (is_host_enabled(musb) && musb->xceiv.default_a) {
if (is_host_enabled(musb) && musb->xceiv->default_a) {
int maxdelay = 30;
u8 devctl, warn = 0;
@ -471,5 +469,7 @@ int musb_platform_exit(struct musb *musb)
clk_disable(musb->clock);
usb_nop_xceiv_unregister();
return 0;
}

View File

@ -112,6 +112,7 @@
#include "davinci.h"
#endif
#define TA_WAIT_BCON(m) max_t(int, (m)->a_wait_bcon, OTG_TIME_A_WAIT_BCON)
unsigned musb_debug;
@ -267,7 +268,7 @@ void musb_load_testpacket(struct musb *musb)
const char *otg_state_string(struct musb *musb)
{
switch (musb->xceiv.state) {
switch (musb->xceiv->state) {
case OTG_STATE_A_IDLE: return "a_idle";
case OTG_STATE_A_WAIT_VRISE: return "a_wait_vrise";
case OTG_STATE_A_WAIT_BCON: return "a_wait_bcon";
@ -287,12 +288,6 @@ const char *otg_state_string(struct musb *musb)
#ifdef CONFIG_USB_MUSB_OTG
/*
* See also USB_OTG_1-3.pdf 6.6.5 Timers
* REVISIT: Are the other timers done in the hardware?
*/
#define TB_ASE0_BRST 100 /* Min 3.125 ms */
/*
* Handles OTG hnp timeouts, such as b_ase0_brst
*/
@ -302,16 +297,18 @@ void musb_otg_timer_func(unsigned long data)
unsigned long flags;
spin_lock_irqsave(&musb->lock, flags);
switch (musb->xceiv.state) {
switch (musb->xceiv->state) {
case OTG_STATE_B_WAIT_ACON:
DBG(1, "HNP: b_wait_acon timeout; back to b_peripheral\n");
musb_g_disconnect(musb);
musb->xceiv.state = OTG_STATE_B_PERIPHERAL;
musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
musb->is_active = 0;
break;
case OTG_STATE_A_SUSPEND:
case OTG_STATE_A_WAIT_BCON:
DBG(1, "HNP: a_wait_bcon timeout; back to a_host\n");
musb_hnp_stop(musb);
DBG(1, "HNP: %s timeout\n", otg_state_string(musb));
musb_set_vbus(musb, 0);
musb->xceiv->state = OTG_STATE_A_WAIT_VFALL;
break;
default:
DBG(1, "HNP: Unhandled mode %s\n", otg_state_string(musb));
@ -320,10 +317,8 @@ void musb_otg_timer_func(unsigned long data)
spin_unlock_irqrestore(&musb->lock, flags);
}
static DEFINE_TIMER(musb_otg_timer, musb_otg_timer_func, 0, 0);
/*
* Stops the B-device HNP state. Caller must take care of locking.
* Stops the HNP transition. Caller must take care of locking.
*/
void musb_hnp_stop(struct musb *musb)
{
@ -331,20 +326,17 @@ void musb_hnp_stop(struct musb *musb)
void __iomem *mbase = musb->mregs;
u8 reg;
switch (musb->xceiv.state) {
DBG(1, "HNP: stop from %s\n", otg_state_string(musb));
switch (musb->xceiv->state) {
case OTG_STATE_A_PERIPHERAL:
case OTG_STATE_A_WAIT_VFALL:
case OTG_STATE_A_WAIT_BCON:
DBG(1, "HNP: Switching back to A-host\n");
musb_g_disconnect(musb);
musb->xceiv.state = OTG_STATE_A_IDLE;
MUSB_HST_MODE(musb);
musb->is_active = 0;
DBG(1, "HNP: back to %s\n", otg_state_string(musb));
break;
case OTG_STATE_B_HOST:
DBG(1, "HNP: Disabling HR\n");
hcd->self.is_b_host = 0;
musb->xceiv.state = OTG_STATE_B_PERIPHERAL;
musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
MUSB_DEV_MODE(musb);
reg = musb_readb(mbase, MUSB_POWER);
reg |= MUSB_POWER_SUSPENDM;
@ -402,7 +394,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
if (devctl & MUSB_DEVCTL_HM) {
#ifdef CONFIG_USB_MUSB_HDRC_HCD
switch (musb->xceiv.state) {
switch (musb->xceiv->state) {
case OTG_STATE_A_SUSPEND:
/* remote wakeup? later, GetPortStatus
* will stop RESUME signaling
@ -425,12 +417,12 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
musb->rh_timer = jiffies
+ msecs_to_jiffies(20);
musb->xceiv.state = OTG_STATE_A_HOST;
musb->xceiv->state = OTG_STATE_A_HOST;
musb->is_active = 1;
usb_hcd_resume_root_hub(musb_to_hcd(musb));
break;
case OTG_STATE_B_WAIT_ACON:
musb->xceiv.state = OTG_STATE_B_PERIPHERAL;
musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
musb->is_active = 1;
MUSB_DEV_MODE(musb);
break;
@ -441,11 +433,11 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
}
#endif
} else {
switch (musb->xceiv.state) {
switch (musb->xceiv->state) {
#ifdef CONFIG_USB_MUSB_HDRC_HCD
case OTG_STATE_A_SUSPEND:
/* possibly DISCONNECT is upcoming */
musb->xceiv.state = OTG_STATE_A_HOST;
musb->xceiv->state = OTG_STATE_A_HOST;
usb_hcd_resume_root_hub(musb_to_hcd(musb));
break;
#endif
@ -490,7 +482,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
*/
musb_writeb(mbase, MUSB_DEVCTL, MUSB_DEVCTL_SESSION);
musb->ep0_stage = MUSB_EP0_START;
musb->xceiv.state = OTG_STATE_A_IDLE;
musb->xceiv->state = OTG_STATE_A_IDLE;
MUSB_HST_MODE(musb);
musb_set_vbus(musb, 1);
@ -516,7 +508,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
* REVISIT: do delays from lots of DEBUG_KERNEL checks
* make trouble here, keeping VBUS < 4.4V ?
*/
switch (musb->xceiv.state) {
switch (musb->xceiv->state) {
case OTG_STATE_A_HOST:
/* recovery is dicey once we've gotten past the
* initial stages of enumeration, but if VBUS
@ -594,37 +586,40 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
if (devctl & MUSB_DEVCTL_LSDEV)
musb->port1_status |= USB_PORT_STAT_LOW_SPEED;
/* indicate new connection to OTG machine */
switch (musb->xceiv->state) {
case OTG_STATE_B_PERIPHERAL:
if (int_usb & MUSB_INTR_SUSPEND) {
DBG(1, "HNP: SUSPEND+CONNECT, now b_host\n");
int_usb &= ~MUSB_INTR_SUSPEND;
goto b_host;
} else
DBG(1, "CONNECT as b_peripheral???\n");
break;
case OTG_STATE_B_WAIT_ACON:
DBG(1, "HNP: CONNECT, now b_host\n");
b_host:
musb->xceiv->state = OTG_STATE_B_HOST;
hcd->self.is_b_host = 1;
musb->ignore_disconnect = 0;
del_timer(&musb->otg_timer);
break;
default:
if ((devctl & MUSB_DEVCTL_VBUS)
== (3 << MUSB_DEVCTL_VBUS_SHIFT)) {
musb->xceiv->state = OTG_STATE_A_HOST;
hcd->self.is_b_host = 0;
}
break;
}
/* poke the root hub */
MUSB_HST_MODE(musb);
if (hcd->status_urb)
usb_hcd_poll_rh_status(hcd);
else
usb_hcd_resume_root_hub(hcd);
MUSB_HST_MODE(musb);
/* indicate new connection to OTG machine */
switch (musb->xceiv.state) {
case OTG_STATE_B_PERIPHERAL:
if (int_usb & MUSB_INTR_SUSPEND) {
DBG(1, "HNP: SUSPEND+CONNECT, now b_host\n");
musb->xceiv.state = OTG_STATE_B_HOST;
hcd->self.is_b_host = 1;
int_usb &= ~MUSB_INTR_SUSPEND;
} else
DBG(1, "CONNECT as b_peripheral???\n");
break;
case OTG_STATE_B_WAIT_ACON:
DBG(1, "HNP: Waiting to switch to b_host state\n");
musb->xceiv.state = OTG_STATE_B_HOST;
hcd->self.is_b_host = 1;
break;
default:
if ((devctl & MUSB_DEVCTL_VBUS)
== (3 << MUSB_DEVCTL_VBUS_SHIFT)) {
musb->xceiv.state = OTG_STATE_A_HOST;
hcd->self.is_b_host = 0;
}
break;
}
DBG(1, "CONNECT (%s) devctl %02x\n",
otg_state_string(musb), devctl);
}
@ -650,7 +645,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
}
} else if (is_peripheral_capable()) {
DBG(1, "BUS RESET as %s\n", otg_state_string(musb));
switch (musb->xceiv.state) {
switch (musb->xceiv->state) {
#ifdef CONFIG_USB_OTG
case OTG_STATE_A_SUSPEND:
/* We need to ignore disconnect on suspend
@ -661,24 +656,27 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
musb_g_reset(musb);
/* FALLTHROUGH */
case OTG_STATE_A_WAIT_BCON: /* OPT TD.4.7-900ms */
DBG(1, "HNP: Setting timer as %s\n",
otg_state_string(musb));
musb_otg_timer.data = (unsigned long)musb;
mod_timer(&musb_otg_timer, jiffies
+ msecs_to_jiffies(100));
/* never use invalid T(a_wait_bcon) */
DBG(1, "HNP: in %s, %d msec timeout\n",
otg_state_string(musb),
TA_WAIT_BCON(musb));
mod_timer(&musb->otg_timer, jiffies
+ msecs_to_jiffies(TA_WAIT_BCON(musb)));
break;
case OTG_STATE_A_PERIPHERAL:
musb_hnp_stop(musb);
musb->ignore_disconnect = 0;
del_timer(&musb->otg_timer);
musb_g_reset(musb);
break;
case OTG_STATE_B_WAIT_ACON:
DBG(1, "HNP: RESET (%s), to b_peripheral\n",
otg_state_string(musb));
musb->xceiv.state = OTG_STATE_B_PERIPHERAL;
musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
musb_g_reset(musb);
break;
#endif
case OTG_STATE_B_IDLE:
musb->xceiv.state = OTG_STATE_B_PERIPHERAL;
musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
/* FALLTHROUGH */
case OTG_STATE_B_PERIPHERAL:
musb_g_reset(musb);
@ -763,7 +761,7 @@ static irqreturn_t musb_stage2_irq(struct musb *musb, u8 int_usb,
MUSB_MODE(musb), devctl);
handled = IRQ_HANDLED;
switch (musb->xceiv.state) {
switch (musb->xceiv->state) {
#ifdef CONFIG_USB_MUSB_HDRC_HCD
case OTG_STATE_A_HOST:
case OTG_STATE_A_SUSPEND:
@ -776,7 +774,16 @@ static irqreturn_t musb_stage2_irq(struct musb *musb, u8 int_usb,
#endif /* HOST */
#ifdef CONFIG_USB_MUSB_OTG
case OTG_STATE_B_HOST:
musb_hnp_stop(musb);
/* REVISIT this behaves for "real disconnect"
* cases; make sure the other transitions from
* from B_HOST act right too. The B_HOST code
* in hnp_stop() is currently not used...
*/
musb_root_disconnect(musb);
musb_to_hcd(musb)->self.is_b_host = 0;
musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
MUSB_DEV_MODE(musb);
musb_g_disconnect(musb);
break;
case OTG_STATE_A_PERIPHERAL:
musb_hnp_stop(musb);
@ -805,26 +812,35 @@ static irqreturn_t musb_stage2_irq(struct musb *musb, u8 int_usb,
otg_state_string(musb), devctl, power);
handled = IRQ_HANDLED;
switch (musb->xceiv.state) {
switch (musb->xceiv->state) {
#ifdef CONFIG_USB_MUSB_OTG
case OTG_STATE_A_PERIPHERAL:
/*
* We cannot stop HNP here, devctl BDEVICE might be
* still set.
/* We also come here if the cable is removed, since
* this silicon doesn't report ID-no-longer-grounded.
*
* We depend on T(a_wait_bcon) to shut us down, and
* hope users don't do anything dicey during this
* undesired detour through A_WAIT_BCON.
*/
musb_hnp_stop(musb);
usb_hcd_resume_root_hub(musb_to_hcd(musb));
musb_root_disconnect(musb);
musb_platform_try_idle(musb, jiffies
+ msecs_to_jiffies(musb->a_wait_bcon
? : OTG_TIME_A_WAIT_BCON));
break;
#endif
case OTG_STATE_B_PERIPHERAL:
musb_g_suspend(musb);
musb->is_active = is_otg_enabled(musb)
&& musb->xceiv.gadget->b_hnp_enable;
&& musb->xceiv->gadget->b_hnp_enable;
if (musb->is_active) {
#ifdef CONFIG_USB_MUSB_OTG
musb->xceiv.state = OTG_STATE_B_WAIT_ACON;
musb->xceiv->state = OTG_STATE_B_WAIT_ACON;
DBG(1, "HNP: Setting timer for b_ase0_brst\n");
musb_otg_timer.data = (unsigned long)musb;
mod_timer(&musb_otg_timer, jiffies
+ msecs_to_jiffies(TB_ASE0_BRST));
mod_timer(&musb->otg_timer, jiffies
+ msecs_to_jiffies(
OTG_TIME_B_ASE0_BRST));
#endif
}
break;
@ -834,9 +850,9 @@ static irqreturn_t musb_stage2_irq(struct musb *musb, u8 int_usb,
+ msecs_to_jiffies(musb->a_wait_bcon));
break;
case OTG_STATE_A_HOST:
musb->xceiv.state = OTG_STATE_A_SUSPEND;
musb->xceiv->state = OTG_STATE_A_SUSPEND;
musb->is_active = is_otg_enabled(musb)
&& musb->xceiv.host->b_hnp_enable;
&& musb->xceiv->host->b_hnp_enable;
break;
case OTG_STATE_B_HOST:
/* Transition to B_PERIPHERAL, see 6.8.2.6 p 44 */
@ -1068,14 +1084,13 @@ static struct fifo_cfg __initdata mode_4_cfg[] = {
{ .hw_ep_num = 8, .style = FIFO_RX, .maxpacket = 512, },
{ .hw_ep_num = 9, .style = FIFO_TX, .maxpacket = 512, },
{ .hw_ep_num = 9, .style = FIFO_RX, .maxpacket = 512, },
{ .hw_ep_num = 10, .style = FIFO_TX, .maxpacket = 512, },
{ .hw_ep_num = 10, .style = FIFO_RX, .maxpacket = 512, },
{ .hw_ep_num = 11, .style = FIFO_TX, .maxpacket = 512, },
{ .hw_ep_num = 11, .style = FIFO_RX, .maxpacket = 512, },
{ .hw_ep_num = 12, .style = FIFO_TX, .maxpacket = 512, },
{ .hw_ep_num = 12, .style = FIFO_RX, .maxpacket = 512, },
{ .hw_ep_num = 13, .style = FIFO_TX, .maxpacket = 512, },
{ .hw_ep_num = 13, .style = FIFO_RX, .maxpacket = 512, },
{ .hw_ep_num = 10, .style = FIFO_TX, .maxpacket = 256, },
{ .hw_ep_num = 10, .style = FIFO_RX, .maxpacket = 64, },
{ .hw_ep_num = 11, .style = FIFO_TX, .maxpacket = 256, },
{ .hw_ep_num = 11, .style = FIFO_RX, .maxpacket = 64, },
{ .hw_ep_num = 12, .style = FIFO_TX, .maxpacket = 256, },
{ .hw_ep_num = 12, .style = FIFO_RX, .maxpacket = 64, },
{ .hw_ep_num = 13, .style = FIFO_RXTX, .maxpacket = 4096, },
{ .hw_ep_num = 14, .style = FIFO_RXTX, .maxpacket = 1024, },
{ .hw_ep_num = 15, .style = FIFO_RXTX, .maxpacket = 1024, },
};
@ -1335,11 +1350,11 @@ static int __init musb_core_init(u16 musb_type, struct musb *musb)
}
if (reg & MUSB_CONFIGDATA_HBRXE) {
strcat(aInfo, ", HB-ISO Rx");
strcat(aInfo, " (X)"); /* no driver support */
musb->hb_iso_rx = true;
}
if (reg & MUSB_CONFIGDATA_HBTXE) {
strcat(aInfo, ", HB-ISO Tx");
strcat(aInfo, " (X)"); /* no driver support */
musb->hb_iso_tx = true;
}
if (reg & MUSB_CONFIGDATA_SOFTCONE)
strcat(aInfo, ", SoftConn");
@ -1481,13 +1496,7 @@ static irqreturn_t generic_interrupt(int irq, void *__hci)
spin_unlock_irqrestore(&musb->lock, flags);
/* REVISIT we sometimes get spurious IRQs on g_ep0
* not clear why...
*/
if (retval != IRQ_HANDLED)
DBG(5, "spurious?\n");
return IRQ_HANDLED;
return retval;
}
#else
@ -1687,8 +1696,9 @@ musb_vbus_store(struct device *dev, struct device_attribute *attr,
}
spin_lock_irqsave(&musb->lock, flags);
musb->a_wait_bcon = val;
if (musb->xceiv.state == OTG_STATE_A_WAIT_BCON)
/* force T(a_wait_bcon) to be zero/unlimited *OR* valid */
musb->a_wait_bcon = val ? max_t(int, val, OTG_TIME_A_WAIT_BCON) : 0 ;
if (musb->xceiv->state == OTG_STATE_A_WAIT_BCON)
musb->is_active = 0;
musb_platform_try_idle(musb, jiffies + msecs_to_jiffies(val));
spin_unlock_irqrestore(&musb->lock, flags);
@ -1706,10 +1716,13 @@ musb_vbus_show(struct device *dev, struct device_attribute *attr, char *buf)
spin_lock_irqsave(&musb->lock, flags);
val = musb->a_wait_bcon;
/* FIXME get_vbus_status() is normally #defined as false...
* and is effectively TUSB-specific.
*/
vbus = musb_platform_get_vbus_status(musb);
spin_unlock_irqrestore(&musb->lock, flags);
return sprintf(buf, "Vbus %s, timeout %lu\n",
return sprintf(buf, "Vbus %s, timeout %lu msec\n",
vbus ? "on" : "off", val);
}
static DEVICE_ATTR(vbus, 0644, musb_vbus_show, musb_vbus_store);
@ -1749,8 +1762,8 @@ static void musb_irq_work(struct work_struct *data)
struct musb *musb = container_of(data, struct musb, irq_work);
static int old_state;
if (musb->xceiv.state != old_state) {
old_state = musb->xceiv.state;
if (musb->xceiv->state != old_state) {
old_state = musb->xceiv->state;
sysfs_notify(&musb->controller->kobj, NULL, "mode");
}
}
@ -1782,6 +1795,7 @@ allocate_instance(struct device *dev,
hcd->uses_new_polling = 1;
musb->vbuserr_retry = VBUSERR_RETRY_COUNT;
musb->a_wait_bcon = OTG_TIME_A_WAIT_BCON;
#else
musb = kzalloc(sizeof *musb, GFP_KERNEL);
if (!musb)
@ -1847,7 +1861,7 @@ static void musb_free(struct musb *musb)
}
#ifdef CONFIG_USB_MUSB_OTG
put_device(musb->xceiv.dev);
put_device(musb->xceiv->dev);
#endif
#ifdef CONFIG_USB_MUSB_HDRC_HCD
@ -1928,10 +1942,18 @@ bad_config:
}
}
/* assume vbus is off */
/* platform adjusts musb->mregs and musb->isr if needed,
* and activates clocks
/* The musb_platform_init() call:
* - adjusts musb->mregs and musb->isr if needed,
* - may initialize an integrated tranceiver
* - initializes musb->xceiv, usually by otg_get_transceiver()
* - activates clocks.
* - stops powering VBUS
* - assigns musb->board_set_vbus if host mode is enabled
*
* There are various transciever configurations. Blackfin,
* DaVinci, TUSB60x0, and others integrate them. OMAP3 uses
* external/discrete ones in various flavors (twl4030 family,
* isp1504, non-OTG, etc) mostly hooking up through ULPI.
*/
musb->isr = generic_interrupt;
status = musb_platform_init(musb);
@ -1968,6 +1990,10 @@ bad_config:
if (status < 0)
goto fail2;
#ifdef CONFIG_USB_OTG
setup_timer(&musb->otg_timer, musb_otg_timer_func, (unsigned long) musb);
#endif
/* Init IRQ workqueue before request_irq */
INIT_WORK(&musb->irq_work, musb_irq_work);
@ -1999,17 +2025,17 @@ bad_config:
? "DMA" : "PIO",
musb->nIrq);
#ifdef CONFIG_USB_MUSB_HDRC_HCD
/* host side needs more setup, except for no-host modes */
if (musb->board_mode != MUSB_PERIPHERAL) {
/* host side needs more setup */
if (is_host_enabled(musb)) {
struct usb_hcd *hcd = musb_to_hcd(musb);
if (musb->board_mode == MUSB_OTG)
otg_set_host(musb->xceiv, &hcd->self);
if (is_otg_enabled(musb))
hcd->self.otg_port = 1;
musb->xceiv.host = &hcd->self;
musb->xceiv->host = &hcd->self;
hcd->power_budget = 2 * (plat->power ? : 250);
}
#endif /* CONFIG_USB_MUSB_HDRC_HCD */
/* For the host-only role, we can activate right away.
* (We expect the ID pin to be forcibly grounded!!)
@ -2017,8 +2043,8 @@ bad_config:
*/
if (!is_otg_enabled(musb) && is_host_enabled(musb)) {
MUSB_HST_MODE(musb);
musb->xceiv.default_a = 1;
musb->xceiv.state = OTG_STATE_A_IDLE;
musb->xceiv->default_a = 1;
musb->xceiv->state = OTG_STATE_A_IDLE;
status = usb_add_hcd(musb_to_hcd(musb), -1, 0);
if (status)
@ -2033,8 +2059,8 @@ bad_config:
} else /* peripheral is enabled */ {
MUSB_DEV_MODE(musb);
musb->xceiv.default_a = 0;
musb->xceiv.state = OTG_STATE_B_IDLE;
musb->xceiv->default_a = 0;
musb->xceiv->state = OTG_STATE_B_IDLE;
status = musb_gadget_setup(musb);
if (status)

View File

@ -40,6 +40,7 @@
#include <linux/interrupt.h>
#include <linux/smp_lock.h>
#include <linux/errno.h>
#include <linux/timer.h>
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/usb/ch9.h>
@ -171,7 +172,8 @@ enum musb_h_ep0_state {
/* peripheral side ep0 states */
enum musb_g_ep0_state {
MUSB_EP0_STAGE_SETUP, /* idle, waiting for setup */
MUSB_EP0_STAGE_IDLE, /* idle, waiting for SETUP */
MUSB_EP0_STAGE_SETUP, /* received SETUP */
MUSB_EP0_STAGE_TX, /* IN data */
MUSB_EP0_STAGE_RX, /* OUT data */
MUSB_EP0_STAGE_STATUSIN, /* (after OUT data) */
@ -179,10 +181,15 @@ enum musb_g_ep0_state {
MUSB_EP0_STAGE_ACKWAIT, /* after zlp, before statusin */
} __attribute__ ((packed));
/* OTG protocol constants */
/*
* OTG protocol constants. See USB OTG 1.3 spec,
* sections 5.5 "Device Timings" and 6.6.5 "Timers".
*/
#define OTG_TIME_A_WAIT_VRISE 100 /* msec (max) */
#define OTG_TIME_A_WAIT_BCON 0 /* 0=infinite; min 1000 msec */
#define OTG_TIME_A_IDLE_BDIS 200 /* msec (min) */
#define OTG_TIME_A_WAIT_BCON 1100 /* min 1 second */
#define OTG_TIME_A_AIDL_BDIS 200 /* min 200 msec */
#define OTG_TIME_B_ASE0_BRST 100 /* min 3.125 ms */
/*************************** REGISTER ACCESS ********************************/
@ -331,6 +338,8 @@ struct musb {
struct list_head control; /* of musb_qh */
struct list_head in_bulk; /* of musb_qh */
struct list_head out_bulk; /* of musb_qh */
struct timer_list otg_timer;
#endif
/* called with IRQs blocked; ON/nonzero implies starting a session,
@ -355,7 +364,7 @@ struct musb {
u16 int_rx;
u16 int_tx;
struct otg_transceiver xceiv;
struct otg_transceiver *xceiv;
int nIrq;
unsigned irq_wake:1;
@ -386,6 +395,9 @@ struct musb {
unsigned is_multipoint:1;
unsigned ignore_disconnect:1; /* during bus resets */
unsigned hb_iso_rx:1; /* high bandwidth iso rx? */
unsigned hb_iso_tx:1; /* high bandwidth iso tx? */
#ifdef C_MP_TX
unsigned bulk_split:1;
#define can_bulk_split(musb,type) \

View File

@ -310,7 +310,7 @@ static void txstate(struct musb *musb, struct musb_request *req)
/* setup DMA, then program endpoint CSR */
request_size = min(request->length,
musb_ep->dma->max_len);
if (request_size <= musb_ep->packet_sz)
if (request_size < musb_ep->packet_sz)
musb_ep->dma->desired_mode = 0;
else
musb_ep->dma->desired_mode = 1;
@ -349,7 +349,8 @@ static void txstate(struct musb *musb, struct musb_request *req)
#elif defined(CONFIG_USB_TI_CPPI_DMA)
/* program endpoint CSR first, then setup DMA */
csr &= ~(MUSB_TXCSR_P_UNDERRUN | MUSB_TXCSR_TXPKTRDY);
csr |= MUSB_TXCSR_MODE | MUSB_TXCSR_DMAENAB;
csr |= MUSB_TXCSR_DMAENAB | MUSB_TXCSR_DMAMODE |
MUSB_TXCSR_MODE;
musb_writew(epio, MUSB_TXCSR,
(MUSB_TXCSR_P_WZC_BITS & ~MUSB_TXCSR_P_UNDERRUN)
| csr);
@ -1405,7 +1406,7 @@ static int musb_gadget_wakeup(struct usb_gadget *gadget)
spin_lock_irqsave(&musb->lock, flags);
switch (musb->xceiv.state) {
switch (musb->xceiv->state) {
case OTG_STATE_B_PERIPHERAL:
/* NOTE: OTG state machine doesn't include B_SUSPENDED;
* that's part of the standard usb 1.1 state machine, and
@ -1507,9 +1508,9 @@ static int musb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA)
{
struct musb *musb = gadget_to_musb(gadget);
if (!musb->xceiv.set_power)
if (!musb->xceiv->set_power)
return -EOPNOTSUPP;
return otg_set_power(&musb->xceiv, mA);
return otg_set_power(musb->xceiv, mA);
}
static int musb_gadget_pullup(struct usb_gadget *gadget, int is_on)
@ -1732,11 +1733,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
spin_lock_irqsave(&musb->lock, flags);
/* REVISIT always use otg_set_peripheral(), handling
* issues including the root hub one below ...
*/
musb->xceiv.gadget = &musb->g;
musb->xceiv.state = OTG_STATE_B_IDLE;
otg_set_peripheral(musb->xceiv, &musb->g);
musb->is_active = 1;
/* FIXME this ignores the softconnect flag. Drivers are
@ -1748,6 +1745,8 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
if (!is_otg_enabled(musb))
musb_start(musb);
otg_set_peripheral(musb->xceiv, &musb->g);
spin_unlock_irqrestore(&musb->lock, flags);
if (is_otg_enabled(musb)) {
@ -1761,8 +1760,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
if (retval < 0) {
DBG(1, "add_hcd failed, %d\n", retval);
spin_lock_irqsave(&musb->lock, flags);
musb->xceiv.gadget = NULL;
musb->xceiv.state = OTG_STATE_UNDEFINED;
otg_set_peripheral(musb->xceiv, NULL);
musb->gadget_driver = NULL;
musb->g.dev.driver = NULL;
spin_unlock_irqrestore(&musb->lock, flags);
@ -1845,8 +1843,9 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
(void) musb_gadget_vbus_draw(&musb->g, 0);
musb->xceiv.state = OTG_STATE_UNDEFINED;
musb->xceiv->state = OTG_STATE_UNDEFINED;
stop_activity(musb, driver);
otg_set_peripheral(musb->xceiv, NULL);
DBG(3, "unregistering driver %s\n", driver->function);
spin_unlock_irqrestore(&musb->lock, flags);
@ -1882,7 +1881,7 @@ EXPORT_SYMBOL(usb_gadget_unregister_driver);
void musb_g_resume(struct musb *musb)
{
musb->is_suspended = 0;
switch (musb->xceiv.state) {
switch (musb->xceiv->state) {
case OTG_STATE_B_IDLE:
break;
case OTG_STATE_B_WAIT_ACON:
@ -1908,10 +1907,10 @@ void musb_g_suspend(struct musb *musb)
devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
DBG(3, "devctl %02x\n", devctl);
switch (musb->xceiv.state) {
switch (musb->xceiv->state) {
case OTG_STATE_B_IDLE:
if ((devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS)
musb->xceiv.state = OTG_STATE_B_PERIPHERAL;
musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
break;
case OTG_STATE_B_PERIPHERAL:
musb->is_suspended = 1;
@ -1957,22 +1956,24 @@ void musb_g_disconnect(struct musb *musb)
spin_lock(&musb->lock);
}
switch (musb->xceiv.state) {
switch (musb->xceiv->state) {
default:
#ifdef CONFIG_USB_MUSB_OTG
DBG(2, "Unhandled disconnect %s, setting a_idle\n",
otg_state_string(musb));
musb->xceiv.state = OTG_STATE_A_IDLE;
musb->xceiv->state = OTG_STATE_A_IDLE;
MUSB_HST_MODE(musb);
break;
case OTG_STATE_A_PERIPHERAL:
musb->xceiv.state = OTG_STATE_A_WAIT_VFALL;
musb->xceiv->state = OTG_STATE_A_WAIT_BCON;
MUSB_HST_MODE(musb);
break;
case OTG_STATE_B_WAIT_ACON:
case OTG_STATE_B_HOST:
#endif
case OTG_STATE_B_PERIPHERAL:
case OTG_STATE_B_IDLE:
musb->xceiv.state = OTG_STATE_B_IDLE;
musb->xceiv->state = OTG_STATE_B_IDLE;
break;
case OTG_STATE_B_SRP_INIT:
break;
@ -2028,10 +2029,10 @@ __acquires(musb->lock)
* or else after HNP, as A-Device
*/
if (devctl & MUSB_DEVCTL_BDEVICE) {
musb->xceiv.state = OTG_STATE_B_PERIPHERAL;
musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
musb->g.is_a_peripheral = 0;
} else if (is_otg_enabled(musb)) {
musb->xceiv.state = OTG_STATE_A_PERIPHERAL;
musb->xceiv->state = OTG_STATE_A_PERIPHERAL;
musb->g.is_a_peripheral = 1;
} else
WARN_ON(1);

View File

@ -4,6 +4,7 @@
* Copyright 2005 Mentor Graphics Corporation
* Copyright (C) 2005-2006 by Texas Instruments
* Copyright (C) 2006-2007 Nokia Corporation
* Copyright (C) 2008-2009 MontaVista Software, Inc. <source@mvista.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -58,7 +59,8 @@
static char *decode_ep0stage(u8 stage)
{
switch (stage) {
case MUSB_EP0_STAGE_SETUP: return "idle";
case MUSB_EP0_STAGE_IDLE: return "idle";
case MUSB_EP0_STAGE_SETUP: return "setup";
case MUSB_EP0_STAGE_TX: return "in";
case MUSB_EP0_STAGE_RX: return "out";
case MUSB_EP0_STAGE_ACKWAIT: return "wait";
@ -628,7 +630,7 @@ irqreturn_t musb_g_ep0_irq(struct musb *musb)
musb_writew(regs, MUSB_CSR0,
csr & ~MUSB_CSR0_P_SENTSTALL);
retval = IRQ_HANDLED;
musb->ep0_state = MUSB_EP0_STAGE_SETUP;
musb->ep0_state = MUSB_EP0_STAGE_IDLE;
csr = musb_readw(regs, MUSB_CSR0);
}
@ -636,7 +638,18 @@ irqreturn_t musb_g_ep0_irq(struct musb *musb)
if (csr & MUSB_CSR0_P_SETUPEND) {
musb_writew(regs, MUSB_CSR0, MUSB_CSR0_P_SVDSETUPEND);
retval = IRQ_HANDLED;
musb->ep0_state = MUSB_EP0_STAGE_SETUP;
/* Transition into the early status phase */
switch (musb->ep0_state) {
case MUSB_EP0_STAGE_TX:
musb->ep0_state = MUSB_EP0_STAGE_STATUSOUT;
break;
case MUSB_EP0_STAGE_RX:
musb->ep0_state = MUSB_EP0_STAGE_STATUSIN;
break;
default:
ERR("SetupEnd came in a wrong ep0stage %s",
decode_ep0stage(musb->ep0_state));
}
csr = musb_readw(regs, MUSB_CSR0);
/* NOTE: request may need completion */
}
@ -697,11 +710,31 @@ irqreturn_t musb_g_ep0_irq(struct musb *musb)
if (req)
musb_g_ep0_giveback(musb, req);
}
/*
* In case when several interrupts can get coalesced,
* check to see if we've already received a SETUP packet...
*/
if (csr & MUSB_CSR0_RXPKTRDY)
goto setup;
retval = IRQ_HANDLED;
musb->ep0_state = MUSB_EP0_STAGE_IDLE;
break;
case MUSB_EP0_STAGE_IDLE:
/*
* This state is typically (but not always) indiscernible
* from the status states since the corresponding interrupts
* tend to happen within too little period of time (with only
* a zero-length packet in between) and so get coalesced...
*/
retval = IRQ_HANDLED;
musb->ep0_state = MUSB_EP0_STAGE_SETUP;
/* FALLTHROUGH */
case MUSB_EP0_STAGE_SETUP:
setup:
if (csr & MUSB_CSR0_RXPKTRDY) {
struct usb_ctrlrequest setup;
int handled = 0;
@ -783,7 +816,7 @@ irqreturn_t musb_g_ep0_irq(struct musb *musb)
stall:
DBG(3, "stall (%d)\n", handled);
musb->ackpend |= MUSB_CSR0_P_SENDSTALL;
musb->ep0_state = MUSB_EP0_STAGE_SETUP;
musb->ep0_state = MUSB_EP0_STAGE_IDLE;
finish:
musb_writew(regs, MUSB_CSR0,
musb->ackpend);
@ -803,7 +836,7 @@ finish:
/* "can't happen" */
WARN_ON(1);
musb_writew(regs, MUSB_CSR0, MUSB_CSR0_P_SENDSTALL);
musb->ep0_state = MUSB_EP0_STAGE_SETUP;
musb->ep0_state = MUSB_EP0_STAGE_IDLE;
break;
}
@ -959,7 +992,7 @@ static int musb_g_ep0_halt(struct usb_ep *e, int value)
csr |= MUSB_CSR0_P_SENDSTALL;
musb_writew(regs, MUSB_CSR0, csr);
musb->ep0_state = MUSB_EP0_STAGE_SETUP;
musb->ep0_state = MUSB_EP0_STAGE_IDLE;
musb->ackpend = 0;
break;
default:

View File

@ -181,6 +181,19 @@ static inline void musb_h_tx_dma_start(struct musb_hw_ep *ep)
musb_writew(ep->regs, MUSB_TXCSR, txcsr);
}
static void musb_ep_set_qh(struct musb_hw_ep *ep, int is_in, struct musb_qh *qh)
{
if (is_in != 0 || ep->is_shared_fifo)
ep->in_qh = qh;
if (is_in == 0 || ep->is_shared_fifo)
ep->out_qh = qh;
}
static struct musb_qh *musb_ep_get_qh(struct musb_hw_ep *ep, int is_in)
{
return is_in ? ep->in_qh : ep->out_qh;
}
/*
* Start the URB at the front of an endpoint's queue
* end must be claimed from the caller.
@ -210,7 +223,6 @@ musb_start_urb(struct musb *musb, int is_in, struct musb_qh *qh)
case USB_ENDPOINT_XFER_CONTROL:
/* control transfers always start with SETUP */
is_in = 0;
hw_ep->out_qh = qh;
musb->ep0_stage = MUSB_EP0_START;
buf = urb->setup_packet;
len = 8;
@ -239,10 +251,7 @@ musb_start_urb(struct musb *musb, int is_in, struct musb_qh *qh)
epnum, buf + offset, len);
/* Configure endpoint */
if (is_in || hw_ep->is_shared_fifo)
hw_ep->in_qh = qh;
else
hw_ep->out_qh = qh;
musb_ep_set_qh(hw_ep, is_in, qh);
musb_ep_program(musb, epnum, urb, !is_in, buf, offset, len);
/* transmit may have more work: start it when it is time */
@ -286,9 +295,8 @@ start:
}
}
/* caller owns controller lock, irqs are blocked */
static void
__musb_giveback(struct musb *musb, struct urb *urb, int status)
/* Context: caller owns controller lock, IRQs are blocked */
static void musb_giveback(struct musb *musb, struct urb *urb, int status)
__releases(musb->lock)
__acquires(musb->lock)
{
@ -321,60 +329,57 @@ __acquires(musb->lock)
spin_lock(&musb->lock);
}
/* for bulk/interrupt endpoints only */
static inline void
musb_save_toggle(struct musb_hw_ep *ep, int is_in, struct urb *urb)
/* For bulk/interrupt endpoints only */
static inline void musb_save_toggle(struct musb_qh *qh, int is_in,
struct urb *urb)
{
struct usb_device *udev = urb->dev;
void __iomem *epio = qh->hw_ep->regs;
u16 csr;
void __iomem *epio = ep->regs;
struct musb_qh *qh;
/* FIXME: the current Mentor DMA code seems to have
/*
* FIXME: the current Mentor DMA code seems to have
* problems getting toggle correct.
*/
if (is_in || ep->is_shared_fifo)
qh = ep->in_qh;
if (is_in)
csr = musb_readw(epio, MUSB_RXCSR) & MUSB_RXCSR_H_DATATOGGLE;
else
qh = ep->out_qh;
csr = musb_readw(epio, MUSB_TXCSR) & MUSB_TXCSR_H_DATATOGGLE;
if (!is_in) {
csr = musb_readw(epio, MUSB_TXCSR);
usb_settoggle(udev, qh->epnum, 1,
(csr & MUSB_TXCSR_H_DATATOGGLE)
? 1 : 0);
} else {
csr = musb_readw(epio, MUSB_RXCSR);
usb_settoggle(udev, qh->epnum, 0,
(csr & MUSB_RXCSR_H_DATATOGGLE)
? 1 : 0);
}
usb_settoggle(urb->dev, qh->epnum, !is_in, csr ? 1 : 0);
}
/* caller owns controller lock, irqs are blocked */
static struct musb_qh *
musb_giveback(struct musb_qh *qh, struct urb *urb, int status)
/*
* Advance this hardware endpoint's queue, completing the specified URB and
* advancing to either the next URB queued to that qh, or else invalidating
* that qh and advancing to the next qh scheduled after the current one.
*
* Context: caller owns controller lock, IRQs are blocked
*/
static void musb_advance_schedule(struct musb *musb, struct urb *urb,
struct musb_hw_ep *hw_ep, int is_in)
{
struct musb_qh *qh = musb_ep_get_qh(hw_ep, is_in);
struct musb_hw_ep *ep = qh->hw_ep;
struct musb *musb = ep->musb;
int is_in = usb_pipein(urb->pipe);
int ready = qh->is_ready;
int status;
status = (urb->status == -EINPROGRESS) ? 0 : urb->status;
/* save toggle eagerly, for paranoia */
switch (qh->type) {
case USB_ENDPOINT_XFER_BULK:
case USB_ENDPOINT_XFER_INT:
musb_save_toggle(ep, is_in, urb);
musb_save_toggle(qh, is_in, urb);
break;
case USB_ENDPOINT_XFER_ISOC:
if (status == 0 && urb->error_count)
if (urb->error_count)
status = -EXDEV;
break;
}
qh->is_ready = 0;
__musb_giveback(musb, urb, status);
musb_giveback(musb, urb, status);
qh->is_ready = ready;
/* reclaim resources (and bandwidth) ASAP; deschedule it, and
@ -388,11 +393,8 @@ musb_giveback(struct musb_qh *qh, struct urb *urb, int status)
else
ep->tx_reinit = 1;
/* clobber old pointers to this qh */
if (is_in || ep->is_shared_fifo)
ep->in_qh = NULL;
else
ep->out_qh = NULL;
/* Clobber old pointers to this qh */
musb_ep_set_qh(ep, is_in, NULL);
qh->hep->hcpriv = NULL;
switch (qh->type) {
@ -421,36 +423,10 @@ musb_giveback(struct musb_qh *qh, struct urb *urb, int status)
break;
}
}
return qh;
}
/*
* Advance this hardware endpoint's queue, completing the specified urb and
* advancing to either the next urb queued to that qh, or else invalidating
* that qh and advancing to the next qh scheduled after the current one.
*
* Context: caller owns controller lock, irqs are blocked
*/
static void
musb_advance_schedule(struct musb *musb, struct urb *urb,
struct musb_hw_ep *hw_ep, int is_in)
{
struct musb_qh *qh;
if (is_in || hw_ep->is_shared_fifo)
qh = hw_ep->in_qh;
else
qh = hw_ep->out_qh;
if (urb->status == -EINPROGRESS)
qh = musb_giveback(qh, urb, 0);
else
qh = musb_giveback(qh, urb, urb->status);
if (qh != NULL && qh->is_ready) {
DBG(4, "... next ep%d %cX urb %p\n",
hw_ep->epnum, is_in ? 'R' : 'T',
next_urb(qh));
hw_ep->epnum, is_in ? 'R' : 'T', next_urb(qh));
musb_start_urb(musb, is_in, qh);
}
}
@ -629,7 +605,8 @@ musb_rx_reinit(struct musb *musb, struct musb_qh *qh, struct musb_hw_ep *ep)
musb_writeb(ep->regs, MUSB_RXTYPE, qh->type_reg);
musb_writeb(ep->regs, MUSB_RXINTERVAL, qh->intv_reg);
/* NOTE: bulk combining rewrites high bits of maxpacket */
musb_writew(ep->regs, MUSB_RXMAXP, qh->maxpacket);
musb_writew(ep->regs, MUSB_RXMAXP,
qh->maxpacket | ((qh->hb_mult - 1) << 11));
ep->rx_reinit = 0;
}
@ -651,9 +628,10 @@ static bool musb_tx_dma_program(struct dma_controller *dma,
csr = musb_readw(epio, MUSB_TXCSR);
if (length > pkt_size) {
mode = 1;
csr |= MUSB_TXCSR_AUTOSET
| MUSB_TXCSR_DMAMODE
| MUSB_TXCSR_DMAENAB;
csr |= MUSB_TXCSR_DMAMODE | MUSB_TXCSR_DMAENAB;
/* autoset shouldn't be set in high bandwidth */
if (qh->hb_mult == 1)
csr |= MUSB_TXCSR_AUTOSET;
} else {
mode = 0;
csr &= ~(MUSB_TXCSR_AUTOSET | MUSB_TXCSR_DMAMODE);
@ -703,15 +681,8 @@ static void musb_ep_program(struct musb *musb, u8 epnum,
void __iomem *mbase = musb->mregs;
struct musb_hw_ep *hw_ep = musb->endpoints + epnum;
void __iomem *epio = hw_ep->regs;
struct musb_qh *qh;
u16 packet_sz;
if (!is_out || hw_ep->is_shared_fifo)
qh = hw_ep->in_qh;
else
qh = hw_ep->out_qh;
packet_sz = qh->maxpacket;
struct musb_qh *qh = musb_ep_get_qh(hw_ep, !is_out);
u16 packet_sz = qh->maxpacket;
DBG(3, "%s hw%d urb %p spd%d dev%d ep%d%s "
"h_addr%02x h_port%02x bytes %d\n",
@ -1129,17 +1100,14 @@ void musb_host_tx(struct musb *musb, u8 epnum)
u16 tx_csr;
size_t length = 0;
size_t offset = 0;
struct urb *urb;
struct musb_hw_ep *hw_ep = musb->endpoints + epnum;
void __iomem *epio = hw_ep->regs;
struct musb_qh *qh = hw_ep->is_shared_fifo ? hw_ep->in_qh
: hw_ep->out_qh;
struct musb_qh *qh = hw_ep->out_qh;
struct urb *urb = next_urb(qh);
u32 status = 0;
void __iomem *mbase = musb->mregs;
struct dma_channel *dma;
urb = next_urb(qh);
musb_ep_select(mbase, epnum);
tx_csr = musb_readw(epio, MUSB_TXCSR);
@ -1427,7 +1395,7 @@ static void musb_bulk_rx_nak_timeout(struct musb *musb, struct musb_hw_ep *ep)
urb->actual_length += dma->actual_len;
dma->actual_len = 0L;
}
musb_save_toggle(ep, 1, urb);
musb_save_toggle(cur_qh, 1, urb);
/* move cur_qh to end of queue */
list_move_tail(&cur_qh->ring, &musb->in_bulk);
@ -1531,6 +1499,10 @@ void musb_host_rx(struct musb *musb, u8 epnum)
/* packet error reported later */
iso_err = true;
}
} else if (rx_csr & MUSB_RXCSR_INCOMPRX) {
DBG(3, "end %d high bandwidth incomplete ISO packet RX\n",
epnum);
status = -EPROTO;
}
/* faults abort the transfer */
@ -1738,7 +1710,11 @@ void musb_host_rx(struct musb *musb, u8 epnum)
val &= ~MUSB_RXCSR_H_AUTOREQ;
else
val |= MUSB_RXCSR_H_AUTOREQ;
val |= MUSB_RXCSR_AUTOCLEAR | MUSB_RXCSR_DMAENAB;
val |= MUSB_RXCSR_DMAENAB;
/* autoclear shouldn't be set in high bandwidth */
if (qh->hb_mult == 1)
val |= MUSB_RXCSR_AUTOCLEAR;
musb_writew(epio, MUSB_RXCSR,
MUSB_RXCSR_H_WZC_BITS | val);
@ -1817,19 +1793,17 @@ static int musb_schedule(
epnum++, hw_ep++) {
int diff;
if (is_in || hw_ep->is_shared_fifo) {
if (hw_ep->in_qh != NULL)
continue;
} else if (hw_ep->out_qh != NULL)
if (musb_ep_get_qh(hw_ep, is_in) != NULL)
continue;
if (hw_ep == musb->bulk_ep)
continue;
if (is_in)
diff = hw_ep->max_packet_sz_rx - qh->maxpacket;
diff = hw_ep->max_packet_sz_rx;
else
diff = hw_ep->max_packet_sz_tx - qh->maxpacket;
diff = hw_ep->max_packet_sz_tx;
diff -= (qh->maxpacket * qh->hb_mult);
if (diff >= 0 && best_diff > diff) {
best_diff = diff;
@ -1932,15 +1906,27 @@ static int musb_urb_enqueue(
qh->is_ready = 1;
qh->maxpacket = le16_to_cpu(epd->wMaxPacketSize);
qh->type = usb_endpoint_type(epd);
/* no high bandwidth support yet */
if (qh->maxpacket & ~0x7ff) {
ret = -EMSGSIZE;
goto done;
/* Bits 11 & 12 of wMaxPacketSize encode high bandwidth multiplier.
* Some musb cores don't support high bandwidth ISO transfers; and
* we don't (yet!) support high bandwidth interrupt transfers.
*/
qh->hb_mult = 1 + ((qh->maxpacket >> 11) & 0x03);
if (qh->hb_mult > 1) {
int ok = (qh->type == USB_ENDPOINT_XFER_ISOC);
if (ok)
ok = (usb_pipein(urb->pipe) && musb->hb_iso_rx)
|| (usb_pipeout(urb->pipe) && musb->hb_iso_tx);
if (!ok) {
ret = -EMSGSIZE;
goto done;
}
qh->maxpacket &= 0x7ff;
}
qh->epnum = usb_endpoint_num(epd);
qh->type = usb_endpoint_type(epd);
/* NOTE: urb->dev->devnum is wrong during SET_ADDRESS */
qh->addr_reg = (u8) usb_pipedevice(urb->pipe);
@ -2052,14 +2038,15 @@ done:
* called with controller locked, irqs blocked
* that hardware queue advances to the next transfer, unless prevented
*/
static int musb_cleanup_urb(struct urb *urb, struct musb_qh *qh, int is_in)
static int musb_cleanup_urb(struct urb *urb, struct musb_qh *qh)
{
struct musb_hw_ep *ep = qh->hw_ep;
void __iomem *epio = ep->regs;
unsigned hw_end = ep->epnum;
void __iomem *regs = ep->musb->mregs;
u16 csr;
int is_in = usb_pipein(urb->pipe);
int status = 0;
u16 csr;
musb_ep_select(regs, hw_end);
@ -2112,14 +2099,14 @@ static int musb_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
{
struct musb *musb = hcd_to_musb(hcd);
struct musb_qh *qh;
struct list_head *sched;
unsigned long flags;
int is_in = usb_pipein(urb->pipe);
int ret;
DBG(4, "urb=%p, dev%d ep%d%s\n", urb,
usb_pipedevice(urb->pipe),
usb_pipeendpoint(urb->pipe),
usb_pipein(urb->pipe) ? "in" : "out");
is_in ? "in" : "out");
spin_lock_irqsave(&musb->lock, flags);
ret = usb_hcd_check_unlink_urb(hcd, urb, status);
@ -2130,47 +2117,25 @@ static int musb_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
if (!qh)
goto done;
/* Any URB not actively programmed into endpoint hardware can be
/*
* Any URB not actively programmed into endpoint hardware can be
* immediately given back; that's any URB not at the head of an
* endpoint queue, unless someday we get real DMA queues. And even
* if it's at the head, it might not be known to the hardware...
*
* Otherwise abort current transfer, pending dma, etc.; urb->status
* Otherwise abort current transfer, pending DMA, etc.; urb->status
* has already been updated. This is a synchronous abort; it'd be
* OK to hold off until after some IRQ, though.
*
* NOTE: qh is invalid unless !list_empty(&hep->urb_list)
*/
if (!qh->is_ready || urb->urb_list.prev != &qh->hep->urb_list)
ret = -EINPROGRESS;
else {
switch (qh->type) {
case USB_ENDPOINT_XFER_CONTROL:
sched = &musb->control;
break;
case USB_ENDPOINT_XFER_BULK:
if (qh->mux == 1) {
if (usb_pipein(urb->pipe))
sched = &musb->in_bulk;
else
sched = &musb->out_bulk;
break;
}
default:
/* REVISIT when we get a schedule tree, periodic
* transfers won't always be at the head of a
* singleton queue...
*/
sched = NULL;
break;
}
}
/* NOTE: qh is invalid unless !list_empty(&hep->urb_list) */
if (ret < 0 || (sched && qh != first_qh(sched))) {
if (!qh->is_ready
|| urb->urb_list.prev != &qh->hep->urb_list
|| musb_ep_get_qh(qh->hw_ep, is_in) != qh) {
int ready = qh->is_ready;
ret = 0;
qh->is_ready = 0;
__musb_giveback(musb, urb, 0);
musb_giveback(musb, urb, 0);
qh->is_ready = ready;
/* If nothing else (usually musb_giveback) is using it
@ -2182,7 +2147,7 @@ static int musb_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
kfree(qh);
}
} else
ret = musb_cleanup_urb(urb, qh, urb->pipe & USB_DIR_IN);
ret = musb_cleanup_urb(urb, qh);
done:
spin_unlock_irqrestore(&musb->lock, flags);
return ret;
@ -2192,13 +2157,11 @@ done:
static void
musb_h_disable(struct usb_hcd *hcd, struct usb_host_endpoint *hep)
{
u8 epnum = hep->desc.bEndpointAddress;
u8 is_in = hep->desc.bEndpointAddress & USB_DIR_IN;
unsigned long flags;
struct musb *musb = hcd_to_musb(hcd);
u8 is_in = epnum & USB_DIR_IN;
struct musb_qh *qh;
struct urb *urb;
struct list_head *sched;
spin_lock_irqsave(&musb->lock, flags);
@ -2206,31 +2169,11 @@ musb_h_disable(struct usb_hcd *hcd, struct usb_host_endpoint *hep)
if (qh == NULL)
goto exit;
switch (qh->type) {
case USB_ENDPOINT_XFER_CONTROL:
sched = &musb->control;
break;
case USB_ENDPOINT_XFER_BULK:
if (qh->mux == 1) {
if (is_in)
sched = &musb->in_bulk;
else
sched = &musb->out_bulk;
break;
}
default:
/* REVISIT when we get a schedule tree, periodic transfers
* won't always be at the head of a singleton queue...
*/
sched = NULL;
break;
}
/* NOTE: qh is invalid unless !list_empty(&hep->urb_list) */
/* NOTE: qh is invalid unless !list_empty(&hep->urb_list) */
/* kick first urb off the hardware, if needed */
/* Kick the first URB off the hardware, if needed */
qh->is_ready = 0;
if (!sched || qh == first_qh(sched)) {
if (musb_ep_get_qh(qh->hw_ep, is_in) == qh) {
urb = next_urb(qh);
/* make software (then hardware) stop ASAP */
@ -2238,7 +2181,7 @@ musb_h_disable(struct usb_hcd *hcd, struct usb_host_endpoint *hep)
urb->status = -ESHUTDOWN;
/* cleanup */
musb_cleanup_urb(urb, qh, urb->pipe & USB_DIR_IN);
musb_cleanup_urb(urb, qh);
/* Then nuke all the others ... and advance the
* queue on hw_ep (e.g. bulk ring) when we're done.
@ -2254,7 +2197,7 @@ musb_h_disable(struct usb_hcd *hcd, struct usb_host_endpoint *hep)
* will activate any of these as it advances.
*/
while (!list_empty(&hep->urb_list))
__musb_giveback(musb, next_urb(qh), -ESHUTDOWN);
musb_giveback(musb, next_urb(qh), -ESHUTDOWN);
hep->hcpriv = NULL;
list_del(&qh->ring);
@ -2293,7 +2236,7 @@ static int musb_bus_suspend(struct usb_hcd *hcd)
{
struct musb *musb = hcd_to_musb(hcd);
if (musb->xceiv.state == OTG_STATE_A_SUSPEND)
if (musb->xceiv->state == OTG_STATE_A_SUSPEND)
return 0;
if (is_host_active(musb) && musb->is_active) {

View File

@ -67,6 +67,7 @@ struct musb_qh {
u8 is_ready; /* safe to modify hw_ep */
u8 type; /* XFERTYPE_* */
u8 epnum;
u8 hb_mult; /* high bandwidth pkts per uf */
u16 maxpacket;
u16 frame; /* for periodic schedule */
unsigned iso_idx; /* in urb->iso_frame_desc[] */

View File

@ -78,18 +78,22 @@ static void musb_port_suspend(struct musb *musb, bool do_suspend)
DBG(3, "Root port suspended, power %02x\n", power);
musb->port1_status |= USB_PORT_STAT_SUSPEND;
switch (musb->xceiv.state) {
switch (musb->xceiv->state) {
case OTG_STATE_A_HOST:
musb->xceiv.state = OTG_STATE_A_SUSPEND;
musb->xceiv->state = OTG_STATE_A_SUSPEND;
musb->is_active = is_otg_enabled(musb)
&& musb->xceiv.host->b_hnp_enable;
&& musb->xceiv->host->b_hnp_enable;
if (musb->is_active)
mod_timer(&musb->otg_timer, jiffies
+ msecs_to_jiffies(
OTG_TIME_A_AIDL_BDIS));
musb_platform_try_idle(musb, 0);
break;
#ifdef CONFIG_USB_MUSB_OTG
case OTG_STATE_B_HOST:
musb->xceiv.state = OTG_STATE_B_WAIT_ACON;
musb->xceiv->state = OTG_STATE_B_WAIT_ACON;
musb->is_active = is_otg_enabled(musb)
&& musb->xceiv.host->b_hnp_enable;
&& musb->xceiv->host->b_hnp_enable;
musb_platform_try_idle(musb, 0);
break;
#endif
@ -116,7 +120,7 @@ static void musb_port_reset(struct musb *musb, bool do_reset)
void __iomem *mbase = musb->mregs;
#ifdef CONFIG_USB_MUSB_OTG
if (musb->xceiv.state == OTG_STATE_B_IDLE) {
if (musb->xceiv->state == OTG_STATE_B_IDLE) {
DBG(2, "HNP: Returning from HNP; no hub reset from b_idle\n");
musb->port1_status &= ~USB_PORT_STAT_RESET;
return;
@ -186,14 +190,23 @@ void musb_root_disconnect(struct musb *musb)
usb_hcd_poll_rh_status(musb_to_hcd(musb));
musb->is_active = 0;
switch (musb->xceiv.state) {
case OTG_STATE_A_HOST:
switch (musb->xceiv->state) {
case OTG_STATE_A_SUSPEND:
musb->xceiv.state = OTG_STATE_A_WAIT_BCON;
#ifdef CONFIG_USB_MUSB_OTG
if (is_otg_enabled(musb)
&& musb->xceiv->host->b_hnp_enable) {
musb->xceiv->state = OTG_STATE_A_PERIPHERAL;
musb->g.is_a_peripheral = 1;
break;
}
#endif
/* FALLTHROUGH */
case OTG_STATE_A_HOST:
musb->xceiv->state = OTG_STATE_A_WAIT_BCON;
musb->is_active = 0;
break;
case OTG_STATE_A_WAIT_VFALL:
musb->xceiv.state = OTG_STATE_B_IDLE;
musb->xceiv->state = OTG_STATE_B_IDLE;
break;
default:
DBG(1, "host disconnect (%s)\n", otg_state_string(musb));
@ -332,7 +345,7 @@ int musb_hub_control(
musb->port1_status |= USB_PORT_STAT_C_SUSPEND << 16;
usb_hcd_poll_rh_status(musb_to_hcd(musb));
/* NOTE: it might really be A_WAIT_BCON ... */
musb->xceiv.state = OTG_STATE_A_HOST;
musb->xceiv->state = OTG_STATE_A_HOST;
}
put_unaligned(cpu_to_le32(musb->port1_status

View File

@ -44,7 +44,6 @@
#define get_cpu_rev() 2
#endif
#define MUSB_TIMEOUT_A_WAIT_BCON 1100
static struct timer_list musb_idle_timer;
@ -61,17 +60,17 @@ static void musb_do_idle(unsigned long _musb)
devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
switch (musb->xceiv.state) {
switch (musb->xceiv->state) {
case OTG_STATE_A_WAIT_BCON:
devctl &= ~MUSB_DEVCTL_SESSION;
musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
if (devctl & MUSB_DEVCTL_BDEVICE) {
musb->xceiv.state = OTG_STATE_B_IDLE;
musb->xceiv->state = OTG_STATE_B_IDLE;
MUSB_DEV_MODE(musb);
} else {
musb->xceiv.state = OTG_STATE_A_IDLE;
musb->xceiv->state = OTG_STATE_A_IDLE;
MUSB_HST_MODE(musb);
}
break;
@ -89,7 +88,7 @@ static void musb_do_idle(unsigned long _musb)
musb->port1_status |= USB_PORT_STAT_C_SUSPEND << 16;
usb_hcd_poll_rh_status(musb_to_hcd(musb));
/* NOTE: it might really be A_WAIT_BCON ... */
musb->xceiv.state = OTG_STATE_A_HOST;
musb->xceiv->state = OTG_STATE_A_HOST;
}
break;
#endif
@ -97,9 +96,9 @@ static void musb_do_idle(unsigned long _musb)
case OTG_STATE_A_HOST:
devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
if (devctl & MUSB_DEVCTL_BDEVICE)
musb->xceiv.state = OTG_STATE_B_IDLE;
musb->xceiv->state = OTG_STATE_B_IDLE;
else
musb->xceiv.state = OTG_STATE_A_WAIT_BCON;
musb->xceiv->state = OTG_STATE_A_WAIT_BCON;
#endif
default:
break;
@ -118,7 +117,7 @@ void musb_platform_try_idle(struct musb *musb, unsigned long timeout)
/* Never idle if active, or when VBUS timeout is not set as host */
if (musb->is_active || ((musb->a_wait_bcon == 0)
&& (musb->xceiv.state == OTG_STATE_A_WAIT_BCON))) {
&& (musb->xceiv->state == OTG_STATE_A_WAIT_BCON))) {
DBG(4, "%s active, deleting timer\n", otg_state_string(musb));
del_timer(&musb_idle_timer);
last_timer = jiffies;
@ -163,8 +162,8 @@ static void omap_set_vbus(struct musb *musb, int is_on)
if (is_on) {
musb->is_active = 1;
musb->xceiv.default_a = 1;
musb->xceiv.state = OTG_STATE_A_WAIT_VRISE;
musb->xceiv->default_a = 1;
musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
devctl |= MUSB_DEVCTL_SESSION;
MUSB_HST_MODE(musb);
@ -175,8 +174,8 @@ static void omap_set_vbus(struct musb *musb, int is_on)
* jumping right to B_IDLE...
*/
musb->xceiv.default_a = 0;
musb->xceiv.state = OTG_STATE_B_IDLE;
musb->xceiv->default_a = 0;
musb->xceiv->state = OTG_STATE_B_IDLE;
devctl &= ~MUSB_DEVCTL_SESSION;
MUSB_DEV_MODE(musb);
@ -188,10 +187,6 @@ static void omap_set_vbus(struct musb *musb, int is_on)
otg_state_string(musb),
musb_readb(musb->mregs, MUSB_DEVCTL));
}
static int omap_set_power(struct otg_transceiver *x, unsigned mA)
{
return 0;
}
static int musb_platform_resume(struct musb *musb);
@ -202,24 +197,6 @@ int musb_platform_set_mode(struct musb *musb, u8 musb_mode)
devctl |= MUSB_DEVCTL_SESSION;
musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
switch (musb_mode) {
#ifdef CONFIG_USB_MUSB_HDRC_HCD
case MUSB_HOST:
otg_set_host(&musb->xceiv, musb->xceiv.host);
break;
#endif
#ifdef CONFIG_USB_GADGET_MUSB_HDRC
case MUSB_PERIPHERAL:
otg_set_peripheral(&musb->xceiv, musb->xceiv.gadget);
break;
#endif
#ifdef CONFIG_USB_MUSB_OTG
case MUSB_OTG:
break;
#endif
default:
return -EINVAL;
}
return 0;
}
@ -231,6 +208,16 @@ int __init musb_platform_init(struct musb *musb)
omap_cfg_reg(AE5_2430_USB0HS_STP);
#endif
/* We require some kind of external transceiver, hooked
* up through ULPI. TWL4030-family PMICs include one,
* which needs a driver, drivers aren't always needed.
*/
musb->xceiv = otg_get_transceiver();
if (!musb->xceiv) {
pr_err("HS USB OTG: no transceiver configured\n");
return -ENODEV;
}
musb_platform_resume(musb);
l = omap_readl(OTG_SYSCONFIG);
@ -240,7 +227,12 @@ int __init musb_platform_init(struct musb *musb)
l &= ~AUTOIDLE; /* disable auto idle */
l &= ~NOIDLE; /* remove possible noidle */
l |= SMARTIDLE; /* enable smart idle */
l |= AUTOIDLE; /* enable auto idle */
/*
* MUSB AUTOIDLE don't work in 3430.
* Workaround by Richard Woodruff/TI
*/
if (!cpu_is_omap3430())
l |= AUTOIDLE; /* enable auto idle */
omap_writel(l, OTG_SYSCONFIG);
l = omap_readl(OTG_INTERFSEL);
@ -257,9 +249,6 @@ int __init musb_platform_init(struct musb *musb)
if (is_host_enabled(musb))
musb->board_set_vbus = omap_set_vbus;
if (is_peripheral_enabled(musb))
musb->xceiv.set_power = omap_set_power;
musb->a_wait_bcon = MUSB_TIMEOUT_A_WAIT_BCON;
setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb);
@ -282,8 +271,7 @@ int musb_platform_suspend(struct musb *musb)
l |= ENABLEWAKEUP; /* enable wakeup */
omap_writel(l, OTG_SYSCONFIG);
if (musb->xceiv.set_suspend)
musb->xceiv.set_suspend(&musb->xceiv, 1);
otg_set_suspend(musb->xceiv, 1);
if (musb->set_clock)
musb->set_clock(musb->clock, 0);
@ -300,8 +288,7 @@ static int musb_platform_resume(struct musb *musb)
if (!musb->clock)
return 0;
if (musb->xceiv.set_suspend)
musb->xceiv.set_suspend(&musb->xceiv, 0);
otg_set_suspend(musb->xceiv, 0);
if (musb->set_clock)
musb->set_clock(musb->clock, 1);

View File

@ -259,6 +259,8 @@ void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *buf)
tusb_fifo_read_unaligned(fifo, buf, len);
}
static struct musb *the_musb;
#ifdef CONFIG_USB_GADGET_MUSB_HDRC
/* This is used by gadget drivers, and OTG transceiver logic, allowing
@ -269,7 +271,7 @@ void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *buf)
*/
static int tusb_draw_power(struct otg_transceiver *x, unsigned mA)
{
struct musb *musb = container_of(x, struct musb, xceiv);
struct musb *musb = the_musb;
void __iomem *tbase = musb->ctrl_base;
u32 reg;
@ -419,7 +421,7 @@ static void musb_do_idle(unsigned long _musb)
spin_lock_irqsave(&musb->lock, flags);
switch (musb->xceiv.state) {
switch (musb->xceiv->state) {
case OTG_STATE_A_WAIT_BCON:
if ((musb->a_wait_bcon != 0)
&& (musb->idle_timeout == 0
@ -483,7 +485,7 @@ void musb_platform_try_idle(struct musb *musb, unsigned long timeout)
/* Never idle if active, or when VBUS timeout is not set as host */
if (musb->is_active || ((musb->a_wait_bcon == 0)
&& (musb->xceiv.state == OTG_STATE_A_WAIT_BCON))) {
&& (musb->xceiv->state == OTG_STATE_A_WAIT_BCON))) {
DBG(4, "%s active, deleting timer\n", otg_state_string(musb));
del_timer(&musb_idle_timer);
last_timer = jiffies;
@ -532,8 +534,8 @@ static void tusb_source_power(struct musb *musb, int is_on)
if (musb->set_clock)
musb->set_clock(musb->clock, 1);
timer = OTG_TIMER_MS(OTG_TIME_A_WAIT_VRISE);
musb->xceiv.default_a = 1;
musb->xceiv.state = OTG_STATE_A_WAIT_VRISE;
musb->xceiv->default_a = 1;
musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
devctl |= MUSB_DEVCTL_SESSION;
conf |= TUSB_DEV_CONF_USB_HOST_MODE;
@ -546,24 +548,24 @@ static void tusb_source_power(struct musb *musb, int is_on)
/* If ID pin is grounded, we want to be a_idle */
otg_stat = musb_readl(tbase, TUSB_DEV_OTG_STAT);
if (!(otg_stat & TUSB_DEV_OTG_STAT_ID_STATUS)) {
switch (musb->xceiv.state) {
switch (musb->xceiv->state) {
case OTG_STATE_A_WAIT_VRISE:
case OTG_STATE_A_WAIT_BCON:
musb->xceiv.state = OTG_STATE_A_WAIT_VFALL;
musb->xceiv->state = OTG_STATE_A_WAIT_VFALL;
break;
case OTG_STATE_A_WAIT_VFALL:
musb->xceiv.state = OTG_STATE_A_IDLE;
musb->xceiv->state = OTG_STATE_A_IDLE;
break;
default:
musb->xceiv.state = OTG_STATE_A_IDLE;
musb->xceiv->state = OTG_STATE_A_IDLE;
}
musb->is_active = 0;
musb->xceiv.default_a = 1;
musb->xceiv->default_a = 1;
MUSB_HST_MODE(musb);
} else {
musb->is_active = 0;
musb->xceiv.default_a = 0;
musb->xceiv.state = OTG_STATE_B_IDLE;
musb->xceiv->default_a = 0;
musb->xceiv->state = OTG_STATE_B_IDLE;
MUSB_DEV_MODE(musb);
}
@ -674,7 +676,7 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)
else
default_a = is_host_enabled(musb);
DBG(2, "Default-%c\n", default_a ? 'A' : 'B');
musb->xceiv.default_a = default_a;
musb->xceiv->default_a = default_a;
tusb_source_power(musb, default_a);
/* Don't allow idling immediately */
@ -686,7 +688,7 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)
if (int_src & TUSB_INT_SRC_VBUS_SENSE_CHNG) {
/* B-dev state machine: no vbus ~= disconnect */
if ((is_otg_enabled(musb) && !musb->xceiv.default_a)
if ((is_otg_enabled(musb) && !musb->xceiv->default_a)
|| !is_host_enabled(musb)) {
#ifdef CONFIG_USB_MUSB_HDRC_HCD
/* ? musb_root_disconnect(musb); */
@ -701,9 +703,9 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)
if (otg_stat & TUSB_DEV_OTG_STAT_SESS_END) {
DBG(1, "Forcing disconnect (no interrupt)\n");
if (musb->xceiv.state != OTG_STATE_B_IDLE) {
if (musb->xceiv->state != OTG_STATE_B_IDLE) {
/* INTR_DISCONNECT can hide... */
musb->xceiv.state = OTG_STATE_B_IDLE;
musb->xceiv->state = OTG_STATE_B_IDLE;
musb->int_usb |= MUSB_INTR_DISCONNECT;
}
musb->is_active = 0;
@ -717,7 +719,7 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)
DBG(2, "vbus change, %s, otg %03x\n",
otg_state_string(musb), otg_stat);
switch (musb->xceiv.state) {
switch (musb->xceiv->state) {
case OTG_STATE_A_IDLE:
DBG(2, "Got SRP, turning on VBUS\n");
musb_set_vbus(musb, 1);
@ -765,7 +767,7 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)
DBG(4, "%s timer, %03x\n", otg_state_string(musb), otg_stat);
switch (musb->xceiv.state) {
switch (musb->xceiv->state) {
case OTG_STATE_A_WAIT_VRISE:
/* VBUS has probably been valid for a while now,
* but may well have bounced out of range a bit
@ -777,7 +779,7 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)
DBG(2, "devctl %02x\n", devctl);
break;
}
musb->xceiv.state = OTG_STATE_A_WAIT_BCON;
musb->xceiv->state = OTG_STATE_A_WAIT_BCON;
musb->is_active = 0;
idle_timeout = jiffies
+ msecs_to_jiffies(musb->a_wait_bcon);
@ -1093,9 +1095,14 @@ int __init musb_platform_init(struct musb *musb)
{
struct platform_device *pdev;
struct resource *mem;
void __iomem *sync;
void __iomem *sync = NULL;
int ret;
usb_nop_xceiv_register();
musb->xceiv = otg_get_transceiver();
if (!musb->xceiv)
return -ENODEV;
pdev = to_platform_device(musb->controller);
/* dma address for async dma */
@ -1106,14 +1113,16 @@ int __init musb_platform_init(struct musb *musb)
mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
if (!mem) {
pr_debug("no sync dma resource?\n");
return -ENODEV;
ret = -ENODEV;
goto done;
}
musb->sync = mem->start;
sync = ioremap(mem->start, mem->end - mem->start + 1);
if (!sync) {
pr_debug("ioremap for sync failed\n");
return -ENOMEM;
ret = -ENOMEM;
goto done;
}
musb->sync_va = sync;
@ -1126,28 +1135,37 @@ int __init musb_platform_init(struct musb *musb)
if (ret) {
printk(KERN_ERR "Could not start tusb6010 (%d)\n",
ret);
return -ENODEV;
goto done;
}
musb->isr = tusb_interrupt;
if (is_host_enabled(musb))
musb->board_set_vbus = tusb_source_power;
if (is_peripheral_enabled(musb))
musb->xceiv.set_power = tusb_draw_power;
if (is_peripheral_enabled(musb)) {
musb->xceiv->set_power = tusb_draw_power;
the_musb = musb;
}
setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb);
done:
if (ret < 0) {
if (sync)
iounmap(sync);
usb_nop_xceiv_unregister();
}
return ret;
}
int musb_platform_exit(struct musb *musb)
{
del_timer_sync(&musb_idle_timer);
the_musb = NULL;
if (musb->board_set_power)
musb->board_set_power(0);
iounmap(musb->sync_va);
usb_nop_xceiv_unregister();
return 0;
}

View File

@ -59,4 +59,18 @@ config NOP_USB_XCEIV
built-in with usb ip or which are autonomous and doesn't require any
phy programming such as ISP1x04 etc.
config USB_LANGWELL_OTG
tristate "Intel Langwell USB OTG dual-role support"
depends on USB && MRST
select USB_OTG
select USB_OTG_UTILS
help
Say Y here if you want to build Intel Langwell USB OTG
transciever driver in kernel. This driver implements role
switch between EHCI host driver and Langwell USB OTG
client driver.
To compile this driver as a module, choose M here: the
module will be called langwell_otg.
endif # USB || OTG

View File

@ -9,6 +9,7 @@ obj-$(CONFIG_USB_OTG_UTILS) += otg.o
obj-$(CONFIG_USB_GPIO_VBUS) += gpio_vbus.o
obj-$(CONFIG_ISP1301_OMAP) += isp1301_omap.o
obj-$(CONFIG_TWL4030_USB) += twl4030-usb.o
obj-$(CONFIG_USB_LANGWELL_OTG) += langwell_otg.o
obj-$(CONFIG_NOP_USB_XCEIV) += nop-usb-xceiv.o
ccflags-$(CONFIG_USB_DEBUG) += -DDEBUG

Some files were not shown because too many files have changed in this diff Show More